use crate::enums::*;
use std::collections::HashMap;
use std::fmt;

#[derive(Debug, Clone)]
pub struct Policy {
    pub flags: u32,
    pub policy_names: HashMap<PolicyOptionName, OptionValue>,
    pub force_names: HashMap<ForceName, bool>,
    pub defaults: HashMap<PolicyOptionName, bool>,
}

#[allow(dead_code)]
impl Policy {
    pub fn new() -> Self {
        Self {
            flags: 0,
            policy_names: HashMap::new(),
            force_names: HashMap::new(),
            defaults: HashMap::new(),
        }
    }

    pub fn bool_to_option_value(input: bool) -> OptionValue {
        if input {
            OptionValue::On
        } else {
            OptionValue::Off
        }
    }

    pub fn is_option_configured(input: OptionValue) -> bool {
        matches!(input, OptionValue::On | OptionValue::Off)
    }

    pub fn is_option_on(input: OptionValue) -> bool {
        matches!(input, OptionValue::On)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.policy_names.insert(name, value);
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.policy_names
            .get(&name)
            .copied()
            .unwrap_or(OptionValue::NotSet)
    }

    pub fn has_policy(&self, name: PolicyOptionName) -> bool {
        self.policy_names.contains_key(&name)
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.policy_names.keys().copied().collect()
    }

    pub fn get_all_force_options(&self) -> Vec<ForceName> {
        self.force_names.keys().copied().collect()
    }

    pub fn is_forced(&self, name: ForceName) -> bool {
        self.force_names.contains_key(&name) && self.force_names[&name]
    }

    pub fn set_force(&mut self, name: ForceName, value: bool) {
        self.force_names.insert(name, value);
    }

    pub fn set_default_value(&mut self, name: PolicyOptionName, value: bool) {
        self.defaults.insert(name, value);
    }

    pub fn get_default_value(&self, name: PolicyOptionName) -> bool {
        self.defaults.get(&name).copied().unwrap_or(false)
    }

    pub fn add(&mut self, name: PolicyOptionName, default_value: bool) {
        self.policy_names.insert(name, OptionValue::NotSet);
        self.defaults.insert(name, default_value);
    }
}

// ProcessDEPPolicy
#[derive(Debug, Clone)]
pub struct ProcessDEPPolicy {
    policy: Policy,
}

impl ProcessDEPPolicy {
    pub fn new() -> Self {
        let mut policy = Policy::new();
        policy.add(PolicyOptionName::Enable, true);
        policy.add(PolicyOptionName::EmulateAtlThunks, false);
        Self { policy }
    }

    pub fn enable(&self) -> OptionValue {
        self.policy.get_policy(PolicyOptionName::Enable)
    }

    pub fn set_enable(&mut self, value: OptionValue) {
        self.policy.set_policy(PolicyOptionName::Enable, value);
    }

    pub fn emulate_atl_thunks(&self) -> OptionValue {
        self.policy.get_policy(PolicyOptionName::EmulateAtlThunks)
    }

    pub fn set_emulate_atl_thunks(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::EmulateAtlThunks, value);
    }

    pub fn flags(&self) -> u32 {
        self.policy.flags
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.policy.flags = flags;
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.policy.set_policy(name, value);
    }
}

// DEPPolicy
#[derive(Debug, Clone)]
pub struct DEPPolicy {
    process_dep_policy: ProcessDEPPolicy,
}

impl DEPPolicy {
    pub fn new() -> Self {
        let mut policy = ProcessDEPPolicy::new();
        policy.policy.force_names.insert(ForceName::DEP, false);
        Self {
            process_dep_policy: policy,
        }
    }

    pub fn override_dep(&self) -> bool {
        self.process_dep_policy.policy.is_forced(ForceName::DEP)
    }

    pub fn set_override_dep(&mut self, value: bool) {
        self.process_dep_policy
            .policy
            .set_force(ForceName::DEP, value);
    }

    pub fn enable(&self) -> OptionValue {
        self.process_dep_policy.enable()
    }

    pub fn set_enable(&mut self, value: OptionValue) {
        self.process_dep_policy.set_enable(value);
    }

    pub fn emulate_atl_thunks(&self) -> OptionValue {
        self.process_dep_policy.emulate_atl_thunks()
    }

    pub fn set_emulate_atl_thunks(&mut self, value: OptionValue) {
        self.process_dep_policy.set_emulate_atl_thunks(value);
    }

    pub fn flags(&self) -> u32 {
        self.process_dep_policy.flags()
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.process_dep_policy.set_flags(flags);
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.process_dep_policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.process_dep_policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.process_dep_policy.set_policy(name, value);
    }
}

// ProcessASLRPolicy
#[derive(Debug, Clone)]
pub struct ProcessASLRPolicy {
    policy: Policy,
}

impl ProcessASLRPolicy {
    pub fn new() -> Self {
        let mut policy = Policy::new();
        policy.add(PolicyOptionName::ForceRelocateImages, false);
        policy.add(PolicyOptionName::RequireInfo, false);
        policy.add(PolicyOptionName::BottomUp, true);
        policy.add(PolicyOptionName::HighEntropy, true);
        Self { policy }
    }

    pub fn force_relocate_images(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::ForceRelocateImages)
    }

    pub fn set_force_relocate_images(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::ForceRelocateImages, value);
    }

    pub fn require_info(&self) -> OptionValue {
        self.policy.get_policy(PolicyOptionName::RequireInfo)
    }

    pub fn set_require_info(&mut self, value: OptionValue) {
        self.policy.set_policy(PolicyOptionName::RequireInfo, value);
    }

    pub fn bottom_up(&self) -> OptionValue {
        self.policy.get_policy(PolicyOptionName::BottomUp)
    }

    pub fn set_bottom_up(&mut self, value: OptionValue) {
        self.policy.set_policy(PolicyOptionName::BottomUp, value);
    }

    pub fn high_entropy(&self) -> OptionValue {
        self.policy.get_policy(PolicyOptionName::HighEntropy)
    }

    pub fn set_high_entropy(&mut self, value: OptionValue) {
        self.policy.set_policy(PolicyOptionName::HighEntropy, value);
    }

    pub fn flags(&self) -> u32 {
        self.policy.flags
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.policy.flags = flags;
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.policy.set_policy(name, value);
    }
}

// ASLRPolicy
#[derive(Debug, Clone)]
pub struct ASLRPolicy {
    process_aslr_policy: ProcessASLRPolicy,
}

impl ASLRPolicy {
    pub fn new() -> Self {
        let mut policy = ProcessASLRPolicy::new();
        policy
            .policy
            .force_names
            .insert(ForceName::ForceRelocateImages, false);
        policy.policy.force_names.insert(ForceName::BottomUp, false);
        policy
            .policy
            .force_names
            .insert(ForceName::HighEntropy, false);
        Self {
            process_aslr_policy: policy,
        }
    }

    pub fn override_force_relocate_images(&self) -> bool {
        self.process_aslr_policy
            .policy
            .is_forced(ForceName::ForceRelocateImages)
    }

    pub fn set_override_force_relocate_images(&mut self, value: bool) {
        self.process_aslr_policy
            .policy
            .set_force(ForceName::ForceRelocateImages, value);
    }

    pub fn override_bottom_up(&self) -> bool {
        self.process_aslr_policy
            .policy
            .is_forced(ForceName::BottomUp)
    }

    pub fn set_override_bottom_up(&mut self, value: bool) {
        self.process_aslr_policy
            .policy
            .set_force(ForceName::BottomUp, value);
    }

    pub fn override_high_entropy(&self) -> bool {
        self.process_aslr_policy
            .policy
            .is_forced(ForceName::HighEntropy)
    }

    pub fn set_override_high_entropy(&mut self, value: bool) {
        self.process_aslr_policy
            .policy
            .set_force(ForceName::HighEntropy, value);
    }

    pub fn force_relocate_images(&self) -> OptionValue {
        self.process_aslr_policy.force_relocate_images()
    }

    pub fn set_force_relocate_images(&mut self, value: OptionValue) {
        self.process_aslr_policy.set_force_relocate_images(value);
    }

    pub fn require_info(&self) -> OptionValue {
        self.process_aslr_policy.require_info()
    }

    pub fn set_require_info(&mut self, value: OptionValue) {
        self.process_aslr_policy.set_require_info(value);
    }

    pub fn bottom_up(&self) -> OptionValue {
        self.process_aslr_policy.bottom_up()
    }

    pub fn set_bottom_up(&mut self, value: OptionValue) {
        self.process_aslr_policy.set_bottom_up(value);
    }

    pub fn high_entropy(&self) -> OptionValue {
        self.process_aslr_policy.high_entropy()
    }

    pub fn set_high_entropy(&mut self, value: OptionValue) {
        self.process_aslr_policy.set_high_entropy(value);
    }

    pub fn flags(&self) -> u32 {
        self.process_aslr_policy.flags()
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.process_aslr_policy.set_flags(flags);
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.process_aslr_policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.process_aslr_policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.process_aslr_policy.set_policy(name, value);
    }
}

// ProcessStrictHandlePolicy
#[derive(Debug, Clone)]
pub struct ProcessStrictHandlePolicy {
    policy: Policy,
}

impl ProcessStrictHandlePolicy {
    pub fn new() -> Self {
        let mut policy = Policy::new();
        policy.add(PolicyOptionName::Enable, false);
        Self { policy }
    }

    pub fn enable(&self) -> OptionValue {
        self.policy.get_policy(PolicyOptionName::Enable)
    }

    pub fn set_enable(&mut self, value: OptionValue) {
        self.policy.set_policy(PolicyOptionName::Enable, value);
    }

    pub fn flags(&self) -> u32 {
        self.policy.flags
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.policy.flags = flags;
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.policy.set_policy(name, value);
    }
}

// StrictHandlePolicy
#[derive(Debug, Clone)]
pub struct StrictHandlePolicy {
    process_strict_handle_policy: ProcessStrictHandlePolicy,
}

impl StrictHandlePolicy {
    pub fn new() -> Self {
        let mut policy = ProcessStrictHandlePolicy::new();
        policy
            .policy
            .force_names
            .insert(ForceName::StrictHandle, false);
        Self {
            process_strict_handle_policy: policy,
        }
    }

    pub fn override_strict_handle(&self) -> bool {
        self.process_strict_handle_policy
            .policy
            .is_forced(ForceName::StrictHandle)
    }

    pub fn set_override_strict_handle(&mut self, value: bool) {
        self.process_strict_handle_policy
            .policy
            .set_force(ForceName::StrictHandle, value);
    }

    pub fn enable(&self) -> OptionValue {
        self.process_strict_handle_policy.enable()
    }

    pub fn set_enable(&mut self, value: OptionValue) {
        self.process_strict_handle_policy.set_enable(value);
    }

    pub fn flags(&self) -> u32 {
        self.process_strict_handle_policy.flags()
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.process_strict_handle_policy.set_flags(flags);
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.process_strict_handle_policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.process_strict_handle_policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.process_strict_handle_policy.set_policy(name, value);
    }
}

// ProcessSystemCallPolicy
#[derive(Debug, Clone)]
pub struct ProcessSystemCallPolicy {
    policy: Policy,
}

impl ProcessSystemCallPolicy {
    pub fn new() -> Self {
        let mut policy = Policy::new();
        policy.add(PolicyOptionName::DisableWin32kSystemCalls, false);
        policy.add(PolicyOptionName::Audit, false);
        policy.add(PolicyOptionName::DisableFsctlSystemCalls, false);
        policy.add(PolicyOptionName::AuditFsctlSystemCalls, false);
        Self { policy }
    }

    pub fn disable_fsctl_system_calls(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::DisableFsctlSystemCalls)
    }

    pub fn set_disable_fsctl_system_calls(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::DisableFsctlSystemCalls, value);
    }

    pub fn audit_fsctl_system_calls(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::AuditFsctlSystemCalls)
    }

    pub fn set_audit_fsctl_system_calls(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::AuditFsctlSystemCalls, value);
    }

    pub fn disable_win32k_system_calls(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::DisableWin32kSystemCalls)
    }

    pub fn set_disable_win32k_system_calls(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::DisableWin32kSystemCalls, value);
    }

    pub fn audit(&self) -> OptionValue {
        self.policy.get_policy(PolicyOptionName::Audit)
    }

    pub fn set_audit(&mut self, value: OptionValue) {
        self.policy.set_policy(PolicyOptionName::Audit, value);
    }

    pub fn flags(&self) -> u32 {
        self.policy.flags
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.policy.flags = flags;
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.policy.set_policy(name, value);
    }
}

// SystemCallPolicy
#[derive(Debug, Clone)]
pub struct SystemCallPolicy {
    process_system_call_policy: ProcessSystemCallPolicy,
}

impl SystemCallPolicy {
    pub fn new() -> Self {
        let mut policy = ProcessSystemCallPolicy::new();
        policy
            .policy
            .force_names
            .insert(ForceName::SystemCall, false);
        policy
            .policy
            .force_names
            .insert(ForceName::DisableFsctlSystem, false);
        Self {
            process_system_call_policy: policy,
        }
    }

    pub fn override_fsctl_system_call(&self) -> bool {
        self.process_system_call_policy
            .policy
            .is_forced(ForceName::DisableFsctlSystem)
    }

    pub fn set_override_fsctl_system_call(&mut self, value: bool) {
        self.process_system_call_policy
            .policy
            .set_force(ForceName::DisableFsctlSystem, value);
    }

    pub fn override_system_call(&self) -> bool {
        self.process_system_call_policy
            .policy
            .is_forced(ForceName::SystemCall)
    }

    pub fn set_override_system_call(&mut self, value: bool) {
        self.process_system_call_policy
            .policy
            .set_force(ForceName::SystemCall, value);
    }

    pub fn disable_fsctl_system_calls(&self) -> OptionValue {
        self.process_system_call_policy.disable_fsctl_system_calls()
    }

    pub fn set_disable_fsctl_system_calls(&mut self, value: OptionValue) {
        self.process_system_call_policy
            .set_disable_fsctl_system_calls(value);
    }

    pub fn audit_fsctl_system_calls(&self) -> OptionValue {
        self.process_system_call_policy.audit_fsctl_system_calls()
    }

    pub fn set_audit_fsctl_system_calls(&mut self, value: OptionValue) {
        self.process_system_call_policy
            .set_audit_fsctl_system_calls(value);
    }

    pub fn disable_win32k_system_calls(&self) -> OptionValue {
        self.process_system_call_policy
            .disable_win32k_system_calls()
    }

    pub fn set_disable_win32k_system_calls(&mut self, value: OptionValue) {
        self.process_system_call_policy
            .set_disable_win32k_system_calls(value);
    }

    pub fn audit(&self) -> OptionValue {
        self.process_system_call_policy.audit()
    }

    pub fn set_audit(&mut self, value: OptionValue) {
        self.process_system_call_policy.set_audit(value);
    }

    pub fn flags(&self) -> u32 {
        self.process_system_call_policy.flags()
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.process_system_call_policy.set_flags(flags);
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.process_system_call_policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.process_system_call_policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.process_system_call_policy.set_policy(name, value);
    }
}

// ProcessExtensionPointPolicy
#[derive(Debug, Clone)]
pub struct ProcessExtensionPointPolicy {
    policy: Policy,
}

impl ProcessExtensionPointPolicy {
    pub fn new() -> Self {
        let mut policy = Policy::new();
        policy.add(PolicyOptionName::DisableExtensionPoints, false);
        Self { policy }
    }

    pub fn disable_extension_points(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::DisableExtensionPoints)
    }

    pub fn set_disable_extension_points(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::DisableExtensionPoints, value);
    }

    pub fn flags(&self) -> u32 {
        self.policy.flags
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.policy.flags = flags;
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.policy.set_policy(name, value);
    }
}

// ExtensionPointPolicy
#[derive(Debug, Clone)]
pub struct ExtensionPointPolicy {
    process_extension_point_policy: ProcessExtensionPointPolicy,
}

impl ExtensionPointPolicy {
    pub fn new() -> Self {
        let mut policy = ProcessExtensionPointPolicy::new();
        policy
            .policy
            .force_names
            .insert(ForceName::ExtensionPoint, false);
        Self {
            process_extension_point_policy: policy,
        }
    }

    pub fn override_extension_point(&self) -> bool {
        self.process_extension_point_policy
            .policy
            .is_forced(ForceName::ExtensionPoint)
    }

    pub fn set_override_extension_point(&mut self, value: bool) {
        self.process_extension_point_policy
            .policy
            .set_force(ForceName::ExtensionPoint, value);
    }

    pub fn disable_extension_points(&self) -> OptionValue {
        self.process_extension_point_policy
            .disable_extension_points()
    }

    pub fn set_disable_extension_points(&mut self, value: OptionValue) {
        self.process_extension_point_policy
            .set_disable_extension_points(value);
    }

    pub fn flags(&self) -> u32 {
        self.process_extension_point_policy.flags()
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.process_extension_point_policy.set_flags(flags);
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.process_extension_point_policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.process_extension_point_policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.process_extension_point_policy.set_policy(name, value);
    }
}

// ProcessDynamicCodePolicy
#[derive(Debug, Clone)]
pub struct ProcessDynamicCodePolicy {
    policy: Policy,
}

impl ProcessDynamicCodePolicy {
    pub fn new() -> Self {
        let mut policy = Policy::new();
        policy.add(PolicyOptionName::BlockDynamicCode, false);
        policy.add(PolicyOptionName::AllowThreadsToOptOut, false);
        policy.add(PolicyOptionName::Audit, false);
        Self { policy }
    }

    pub fn block_dynamic_code(&self) -> OptionValue {
        self.policy.get_policy(PolicyOptionName::BlockDynamicCode)
    }

    pub fn set_block_dynamic_code(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::BlockDynamicCode, value);
    }

    pub fn allow_threads_to_opt_out(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::AllowThreadsToOptOut)
    }

    pub fn set_allow_threads_to_opt_out(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::AllowThreadsToOptOut, value);
    }

    pub fn audit(&self) -> OptionValue {
        self.policy.get_policy(PolicyOptionName::Audit)
    }

    pub fn set_audit(&mut self, value: OptionValue) {
        self.policy.set_policy(PolicyOptionName::Audit, value);
    }

    pub fn flags(&self) -> u32 {
        self.policy.flags
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.policy.flags = flags;
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.policy.set_policy(name, value);
    }
}

// DynamicCodePolicy
#[derive(Debug, Clone)]
pub struct DynamicCodePolicy {
    process_dynamic_code_policy: ProcessDynamicCodePolicy,
}

impl DynamicCodePolicy {
    pub fn new() -> Self {
        let mut policy = ProcessDynamicCodePolicy::new();
        policy
            .policy
            .force_names
            .insert(ForceName::DynamicCode, false);
        Self {
            process_dynamic_code_policy: policy,
        }
    }

    pub fn override_dynamic_code(&self) -> bool {
        self.process_dynamic_code_policy
            .policy
            .is_forced(ForceName::DynamicCode)
    }

    pub fn set_override_dynamic_code(&mut self, value: bool) {
        self.process_dynamic_code_policy
            .policy
            .set_force(ForceName::DynamicCode, value);
    }

    pub fn block_dynamic_code(&self) -> OptionValue {
        self.process_dynamic_code_policy.block_dynamic_code()
    }

    pub fn set_block_dynamic_code(&mut self, value: OptionValue) {
        self.process_dynamic_code_policy
            .set_block_dynamic_code(value);
    }

    pub fn allow_threads_to_opt_out(&self) -> OptionValue {
        self.process_dynamic_code_policy.allow_threads_to_opt_out()
    }

    pub fn set_allow_threads_to_opt_out(&mut self, value: OptionValue) {
        self.process_dynamic_code_policy
            .set_allow_threads_to_opt_out(value);
    }

    pub fn audit(&self) -> OptionValue {
        self.process_dynamic_code_policy.audit()
    }

    pub fn set_audit(&mut self, value: OptionValue) {
        self.process_dynamic_code_policy.set_audit(value);
    }

    pub fn flags(&self) -> u32 {
        self.process_dynamic_code_policy.flags()
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.process_dynamic_code_policy.set_flags(flags);
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.process_dynamic_code_policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.process_dynamic_code_policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.process_dynamic_code_policy.set_policy(name, value);
    }
}

// ProcessCFGPolicy
#[derive(Debug, Clone)]
pub struct ProcessCFGPolicy {
    policy: Policy,
}

impl ProcessCFGPolicy {
    pub fn new() -> Self {
        let mut policy = Policy::new();
        policy.add(PolicyOptionName::Enable, true);
        policy.add(PolicyOptionName::SuppressExports, false);
        policy.add(PolicyOptionName::StrictControlFlowGuard, false);
        Self { policy }
    }

    pub fn enable(&self) -> OptionValue {
        self.policy.get_policy(PolicyOptionName::Enable)
    }

    pub fn set_enable(&mut self, value: OptionValue) {
        self.policy.set_policy(PolicyOptionName::Enable, value);
    }

    pub fn suppress_exports(&self) -> OptionValue {
        self.policy.get_policy(PolicyOptionName::SuppressExports)
    }

    pub fn set_suppress_exports(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::SuppressExports, value);
    }

    pub fn strict_control_flow_guard(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::StrictControlFlowGuard)
    }

    pub fn set_strict_control_flow_guard(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::StrictControlFlowGuard, value);
    }

    pub fn flags(&self) -> u32 {
        self.policy.flags
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.policy.flags = flags;
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.policy.set_policy(name, value);
    }
}

// CFGPolicy
#[derive(Debug, Clone)]
pub struct CFGPolicy {
    process_cfg_policy: ProcessCFGPolicy,
}

impl CFGPolicy {
    pub fn new() -> Self {
        let mut policy = ProcessCFGPolicy::new();
        policy.policy.force_names.insert(ForceName::CFG, false);
        policy
            .policy
            .force_names
            .insert(ForceName::StrictCFG, false);
        Self {
            process_cfg_policy: policy,
        }
    }

    pub fn override_cfg(&self) -> bool {
        self.process_cfg_policy.policy.is_forced(ForceName::CFG)
    }

    pub fn set_override_cfg(&mut self, value: bool) {
        self.process_cfg_policy
            .policy
            .set_force(ForceName::CFG, value);
    }

    pub fn override_strict_cfg(&self) -> bool {
        self.process_cfg_policy
            .policy
            .is_forced(ForceName::StrictCFG)
    }

    pub fn set_override_strict_cfg(&mut self, value: bool) {
        self.process_cfg_policy
            .policy
            .set_force(ForceName::StrictCFG, value);
    }

    pub fn enable(&self) -> OptionValue {
        self.process_cfg_policy.enable()
    }

    pub fn set_enable(&mut self, value: OptionValue) {
        self.process_cfg_policy.set_enable(value);
    }

    pub fn suppress_exports(&self) -> OptionValue {
        self.process_cfg_policy.suppress_exports()
    }

    pub fn set_suppress_exports(&mut self, value: OptionValue) {
        self.process_cfg_policy.set_suppress_exports(value);
    }

    pub fn strict_control_flow_guard(&self) -> OptionValue {
        self.process_cfg_policy.strict_control_flow_guard()
    }

    pub fn set_strict_control_flow_guard(&mut self, value: OptionValue) {
        self.process_cfg_policy.set_strict_control_flow_guard(value);
    }

    pub fn flags(&self) -> u32 {
        self.process_cfg_policy.flags()
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.process_cfg_policy.set_flags(flags);
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.process_cfg_policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.process_cfg_policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.process_cfg_policy.set_policy(name, value);
    }
}

// ProcessBinarySignaturePolicy
#[derive(Debug, Clone)]
pub struct ProcessBinarySignaturePolicy {
    policy: Policy,
}

impl ProcessBinarySignaturePolicy {
    pub fn new() -> Self {
        let mut policy = Policy::new();
        policy.add(PolicyOptionName::MicrosoftSignedOnly, false);
        policy.add(PolicyOptionName::AllowStoreSignedBinaries, false);
        policy.add(PolicyOptionName::Audit, false);
        policy.add(PolicyOptionName::AuditStoreSigned, false);
        Self { policy }
    }

    pub fn microsoft_signed_only(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::MicrosoftSignedOnly)
    }

    pub fn set_microsoft_signed_only(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::MicrosoftSignedOnly, value);
    }

    pub fn allow_store_signed_binaries(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::AllowStoreSignedBinaries)
    }

    pub fn set_allow_store_signed_binaries(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::AllowStoreSignedBinaries, value);
    }

    pub fn audit(&self) -> OptionValue {
        self.policy.get_policy(PolicyOptionName::Audit)
    }

    pub fn set_audit(&mut self, value: OptionValue) {
        self.policy.set_policy(PolicyOptionName::Audit, value);
    }

    pub fn audit_store_signed(&self) -> OptionValue {
        self.policy.get_policy(PolicyOptionName::AuditStoreSigned)
    }

    pub fn set_audit_store_signed(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::AuditStoreSigned, value);
    }

    pub fn flags(&self) -> u32 {
        self.policy.flags
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.policy.flags = flags;
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.policy.set_policy(name, value);
    }
}

// BinarySignaturePolicy
#[derive(Debug, Clone)]
pub struct BinarySignaturePolicy {
    process_binary_signature_policy: ProcessBinarySignaturePolicy,
}

impl BinarySignaturePolicy {
    pub fn new() -> Self {
        let mut policy = ProcessBinarySignaturePolicy::new();
        policy
            .policy
            .add(PolicyOptionName::EnforceModuleDependencySigning, false);
        policy
            .policy
            .add(PolicyOptionName::AuditEnforceModuleDependencySigning, false);
        policy
            .policy
            .force_names
            .insert(ForceName::MicrosoftSignedOnly, false);
        policy
            .policy
            .force_names
            .insert(ForceName::EnforceModuleDependencySigning, false);
        Self {
            process_binary_signature_policy: policy,
        }
    }

    pub fn enforce_module_dependency_signing(&self) -> OptionValue {
        self.process_binary_signature_policy
            .policy
            .get_policy(PolicyOptionName::EnforceModuleDependencySigning)
    }

    pub fn set_enforce_module_dependency_signing(&mut self, value: OptionValue) {
        self.process_binary_signature_policy
            .policy
            .set_policy(PolicyOptionName::EnforceModuleDependencySigning, value);
    }

    pub fn audit_enforce_module_dependency_signing(&self) -> OptionValue {
        self.process_binary_signature_policy
            .policy
            .get_policy(PolicyOptionName::AuditEnforceModuleDependencySigning)
    }

    pub fn set_audit_enforce_module_dependency_signing(&mut self, value: OptionValue) {
        self.process_binary_signature_policy
            .policy
            .set_policy(PolicyOptionName::AuditEnforceModuleDependencySigning, value);
    }

    pub fn override_microsoft_signed_only(&self) -> bool {
        self.process_binary_signature_policy
            .policy
            .is_forced(ForceName::MicrosoftSignedOnly)
    }

    pub fn set_override_microsoft_signed_only(&mut self, value: bool) {
        self.process_binary_signature_policy
            .policy
            .set_force(ForceName::MicrosoftSignedOnly, value);
    }

    pub fn override_enforce_module_dependency_signing(&self) -> bool {
        self.process_binary_signature_policy
            .policy
            .is_forced(ForceName::EnforceModuleDependencySigning)
    }

    pub fn set_override_enforce_module_dependency_signing(&mut self, value: bool) {
        self.process_binary_signature_policy
            .policy
            .set_force(ForceName::EnforceModuleDependencySigning, value);
    }

    pub fn microsoft_signed_only(&self) -> OptionValue {
        self.process_binary_signature_policy.microsoft_signed_only()
    }

    pub fn set_microsoft_signed_only(&mut self, value: OptionValue) {
        self.process_binary_signature_policy
            .set_microsoft_signed_only(value);
    }

    pub fn allow_store_signed_binaries(&self) -> OptionValue {
        self.process_binary_signature_policy
            .allow_store_signed_binaries()
    }

    pub fn set_allow_store_signed_binaries(&mut self, value: OptionValue) {
        self.process_binary_signature_policy
            .set_allow_store_signed_binaries(value);
    }

    pub fn audit(&self) -> OptionValue {
        self.process_binary_signature_policy.audit()
    }

    pub fn set_audit(&mut self, value: OptionValue) {
        self.process_binary_signature_policy.set_audit(value);
    }

    pub fn audit_store_signed(&self) -> OptionValue {
        self.process_binary_signature_policy.audit_store_signed()
    }

    pub fn set_audit_store_signed(&mut self, value: OptionValue) {
        self.process_binary_signature_policy
            .set_audit_store_signed(value);
    }

    pub fn flags(&self) -> u32 {
        self.process_binary_signature_policy.flags()
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.process_binary_signature_policy.set_flags(flags);
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.process_binary_signature_policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.process_binary_signature_policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.process_binary_signature_policy.set_policy(name, value);
    }
}

// ProcessFontDisablePolicy
#[derive(Debug, Clone)]
pub struct ProcessFontDisablePolicy {
    policy: Policy,
}

impl ProcessFontDisablePolicy {
    pub fn new() -> Self {
        let mut policy = Policy::new();
        policy.add(PolicyOptionName::DisableNonSystemFonts, false);
        policy.add(PolicyOptionName::Audit, false);
        Self { policy }
    }

    pub fn disable_non_system_fonts(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::DisableNonSystemFonts)
    }

    pub fn set_disable_non_system_fonts(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::DisableNonSystemFonts, value);
    }

    pub fn audit(&self) -> OptionValue {
        self.policy.get_policy(PolicyOptionName::Audit)
    }

    pub fn set_audit(&mut self, value: OptionValue) {
        self.policy.set_policy(PolicyOptionName::Audit, value);
    }

    pub fn flags(&self) -> u32 {
        self.policy.flags
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.policy.flags = flags;
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.policy.set_policy(name, value);
    }
}

// FontDisablePolicy
#[derive(Debug, Clone)]
pub struct FontDisablePolicy {
    process_font_disable_policy: ProcessFontDisablePolicy,
}

impl FontDisablePolicy {
    pub fn new() -> Self {
        let mut policy = ProcessFontDisablePolicy::new();
        policy
            .policy
            .force_names
            .insert(ForceName::FontDisable, false);
        Self {
            process_font_disable_policy: policy,
        }
    }

    pub fn override_font_disable(&self) -> bool {
        self.process_font_disable_policy
            .policy
            .is_forced(ForceName::FontDisable)
    }

    pub fn set_override_font_disable(&mut self, value: bool) {
        self.process_font_disable_policy
            .policy
            .set_force(ForceName::FontDisable, value);
    }

    pub fn disable_non_system_fonts(&self) -> OptionValue {
        self.process_font_disable_policy.disable_non_system_fonts()
    }

    pub fn set_disable_non_system_fonts(&mut self, value: OptionValue) {
        self.process_font_disable_policy
            .set_disable_non_system_fonts(value);
    }

    pub fn audit(&self) -> OptionValue {
        self.process_font_disable_policy.audit()
    }

    pub fn set_audit(&mut self, value: OptionValue) {
        self.process_font_disable_policy.set_audit(value);
    }

    pub fn flags(&self) -> u32 {
        self.process_font_disable_policy.flags()
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.process_font_disable_policy.set_flags(flags);
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.process_font_disable_policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.process_font_disable_policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.process_font_disable_policy.set_policy(name, value);
    }
}

// ProcessImageLoadPolicy
#[derive(Debug, Clone)]
pub struct ProcessImageLoadPolicy {
    policy: Policy,
}

impl ProcessImageLoadPolicy {
    pub fn new() -> Self {
        let mut policy = Policy::new();
        policy.add(PolicyOptionName::BlockRemoteImageLoads, false);
        policy.add(PolicyOptionName::BlockLowLabelImageLoads, false);
        policy.add(PolicyOptionName::PreferSystem32, false);
        policy.add(PolicyOptionName::AuditRemoteImageLoads, false);
        policy.add(PolicyOptionName::AuditLowLabelImageLoads, false);
        policy.add(PolicyOptionName::AuditPreferSystem32, false);
        Self { policy }
    }

    pub fn block_remote_image_loads(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::BlockRemoteImageLoads)
    }

    pub fn set_block_remote_image_loads(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::BlockRemoteImageLoads, value);
    }

    pub fn block_low_label_image_loads(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::BlockLowLabelImageLoads)
    }

    pub fn set_block_low_label_image_loads(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::BlockLowLabelImageLoads, value);
    }

    pub fn prefer_system32(&self) -> OptionValue {
        self.policy.get_policy(PolicyOptionName::PreferSystem32)
    }

    pub fn set_prefer_system32(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::PreferSystem32, value);
    }

    pub fn audit_remote_image_loads(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::AuditRemoteImageLoads)
    }

    pub fn set_audit_remote_image_loads(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::AuditRemoteImageLoads, value);
    }

    pub fn audit_low_label_image_loads(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::AuditLowLabelImageLoads)
    }

    pub fn set_audit_low_label_image_loads(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::AuditLowLabelImageLoads, value);
    }

    pub fn audit_prefer_system32(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::AuditPreferSystem32)
    }

    pub fn set_audit_prefer_system32(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::AuditPreferSystem32, value);
    }

    pub fn flags(&self) -> u32 {
        self.policy.flags
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.policy.flags = flags;
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.policy.set_policy(name, value);
    }
}

// ImageLoadPolicy
#[derive(Debug, Clone)]
pub struct ImageLoadPolicy {
    process_image_load_policy: ProcessImageLoadPolicy,
}

impl ImageLoadPolicy {
    pub fn new() -> Self {
        let mut policy = ProcessImageLoadPolicy::new();
        policy
            .policy
            .force_names
            .insert(ForceName::BlockRemoteImageLoads, false);
        policy
            .policy
            .force_names
            .insert(ForceName::BlockLowLabel, false);
        policy
            .policy
            .force_names
            .insert(ForceName::PreferSystem32, false);
        Self {
            process_image_load_policy: policy,
        }
    }

    pub fn override_block_remote_image_loads(&self) -> bool {
        self.process_image_load_policy
            .policy
            .is_forced(ForceName::BlockRemoteImageLoads)
    }

    pub fn set_override_block_remote_image_loads(&mut self, value: bool) {
        self.process_image_load_policy
            .policy
            .set_force(ForceName::BlockRemoteImageLoads, value);
    }

    pub fn override_block_low_label(&self) -> bool {
        self.process_image_load_policy
            .policy
            .is_forced(ForceName::BlockLowLabel)
    }

    pub fn set_override_block_low_label(&mut self, value: bool) {
        self.process_image_load_policy
            .policy
            .set_force(ForceName::BlockLowLabel, value);
    }

    pub fn override_prefer_system32(&self) -> bool {
        self.process_image_load_policy
            .policy
            .is_forced(ForceName::PreferSystem32)
    }

    pub fn set_override_prefer_system32(&mut self, value: bool) {
        self.process_image_load_policy
            .policy
            .set_force(ForceName::PreferSystem32, value);
    }

    pub fn block_remote_image_loads(&self) -> OptionValue {
        self.process_image_load_policy.block_remote_image_loads()
    }

    pub fn set_block_remote_image_loads(&mut self, value: OptionValue) {
        self.process_image_load_policy
            .set_block_remote_image_loads(value);
    }

    pub fn block_low_label_image_loads(&self) -> OptionValue {
        self.process_image_load_policy.block_low_label_image_loads()
    }

    pub fn set_block_low_label_image_loads(&mut self, value: OptionValue) {
        self.process_image_load_policy
            .set_block_low_label_image_loads(value);
    }

    pub fn prefer_system32(&self) -> OptionValue {
        self.process_image_load_policy.prefer_system32()
    }

    pub fn set_prefer_system32(&mut self, value: OptionValue) {
        self.process_image_load_policy.set_prefer_system32(value);
    }

    pub fn audit_remote_image_loads(&self) -> OptionValue {
        self.process_image_load_policy.audit_remote_image_loads()
    }

    pub fn set_audit_remote_image_loads(&mut self, value: OptionValue) {
        self.process_image_load_policy
            .set_audit_remote_image_loads(value);
    }

    pub fn audit_low_label_image_loads(&self) -> OptionValue {
        self.process_image_load_policy.audit_low_label_image_loads()
    }

    pub fn set_audit_low_label_image_loads(&mut self, value: OptionValue) {
        self.process_image_load_policy
            .set_audit_low_label_image_loads(value);
    }

    pub fn audit_prefer_system32(&self) -> OptionValue {
        self.process_image_load_policy.audit_prefer_system32()
    }

    pub fn set_audit_prefer_system32(&mut self, value: OptionValue) {
        self.process_image_load_policy
            .set_audit_prefer_system32(value);
    }

    pub fn flags(&self) -> u32 {
        self.process_image_load_policy.flags()
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.process_image_load_policy.set_flags(flags);
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.process_image_load_policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.process_image_load_policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.process_image_load_policy.set_policy(name, value);
    }
}

// ProcessPayloadPolicy
#[derive(Debug, Clone)]
pub struct ProcessPayloadPolicy {
    policy: Policy,
}

impl ProcessPayloadPolicy {
    pub fn new() -> Self {
        let mut policy = Policy::new();
        policy.add(PolicyOptionName::EnableExportAddressFilter, false);
        policy.add(PolicyOptionName::AuditEnableExportAddressFilter, false);
        policy.add(PolicyOptionName::EnableExportAddressFilterPlus, false);
        policy.add(PolicyOptionName::AuditEnableExportAddressFilterPlus, false);
        policy.add(PolicyOptionName::EnableImportAddressFilter, false);
        policy.add(PolicyOptionName::AuditEnableImportAddressFilter, false);
        policy.add(PolicyOptionName::EnableRopStackPivot, false);
        policy.add(PolicyOptionName::AuditEnableRopStackPivot, false);
        policy.add(PolicyOptionName::EnableRopCallerCheck, false);
        policy.add(PolicyOptionName::AuditEnableRopCallerCheck, false);
        policy.add(PolicyOptionName::EnableRopSimExec, false);
        policy.add(PolicyOptionName::AuditEnableRopSimExec, false);
        Self { policy }
    }

    pub fn enable_export_address_filter(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::EnableExportAddressFilter)
    }

    pub fn set_enable_export_address_filter(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::EnableExportAddressFilter, value);
    }

    pub fn audit_enable_export_address_filter(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::AuditEnableExportAddressFilter)
    }

    pub fn set_audit_enable_export_address_filter(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::AuditEnableExportAddressFilter, value);
    }

    pub fn enable_export_address_filter_plus(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::EnableExportAddressFilterPlus)
    }

    pub fn set_enable_export_address_filter_plus(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::EnableExportAddressFilterPlus, value);
    }

    pub fn audit_enable_export_address_filter_plus(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::AuditEnableExportAddressFilterPlus)
    }

    pub fn set_audit_enable_export_address_filter_plus(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::AuditEnableExportAddressFilterPlus, value);
    }

    pub fn enable_import_address_filter(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::EnableImportAddressFilter)
    }

    pub fn set_enable_import_address_filter(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::EnableImportAddressFilter, value);
    }

    pub fn audit_enable_import_address_filter(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::AuditEnableImportAddressFilter)
    }

    pub fn set_audit_enable_import_address_filter(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::AuditEnableImportAddressFilter, value);
    }

    pub fn enable_rop_stack_pivot(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::EnableRopStackPivot)
    }

    pub fn set_enable_rop_stack_pivot(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::EnableRopStackPivot, value);
    }

    pub fn audit_enable_rop_stack_pivot(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::AuditEnableRopStackPivot)
    }

    pub fn set_audit_enable_rop_stack_pivot(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::AuditEnableRopStackPivot, value);
    }

    pub fn enable_rop_caller_check(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::EnableRopCallerCheck)
    }

    pub fn set_enable_rop_caller_check(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::EnableRopCallerCheck, value);
    }

    pub fn audit_enable_rop_caller_check(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::AuditEnableRopCallerCheck)
    }

    pub fn set_audit_enable_rop_caller_check(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::AuditEnableRopCallerCheck, value);
    }

    pub fn enable_rop_sim_exec(&self) -> OptionValue {
        self.policy.get_policy(PolicyOptionName::EnableRopSimExec)
    }

    pub fn set_enable_rop_sim_exec(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::EnableRopSimExec, value);
    }

    pub fn audit_enable_rop_sim_exec(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::AuditEnableRopSimExec)
    }

    pub fn set_audit_enable_rop_sim_exec(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::AuditEnableRopSimExec, value);
    }

    pub fn flags(&self) -> u32 {
        self.policy.flags
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.policy.flags = flags;
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.policy.set_policy(name, value);
    }
}

// PayloadPolicy
#[derive(Debug, Clone)]
pub struct PayloadPolicy {
    process_payload_policy: ProcessPayloadPolicy,
    pub eaf_modules: Vec<String>,
}

impl PayloadPolicy {
    pub fn new() -> Self {
        let mut policy = ProcessPayloadPolicy::new();
        policy
            .policy
            .force_names
            .insert(ForceName::EnableExportAddressFilter, false);
        policy
            .policy
            .force_names
            .insert(ForceName::EnableExportAddressFilterPlus, false);
        policy
            .policy
            .force_names
            .insert(ForceName::EnableImportAddressFilter, false);
        policy
            .policy
            .force_names
            .insert(ForceName::EnableRopStackPivot, false);
        policy
            .policy
            .force_names
            .insert(ForceName::EnableRopCallerCheck, false);
        policy
            .policy
            .force_names
            .insert(ForceName::EnableRopSimExec, false);
        Self {
            process_payload_policy: policy,
            eaf_modules: Vec::new(),
        }
    }

    pub fn override_enable_export_address_filter(&self) -> bool {
        self.process_payload_policy
            .policy
            .is_forced(ForceName::EnableExportAddressFilter)
    }

    pub fn set_override_enable_export_address_filter(&mut self, value: bool) {
        self.process_payload_policy
            .policy
            .set_force(ForceName::EnableExportAddressFilter, value);
    }

    pub fn override_enable_export_address_filter_plus(&self) -> bool {
        self.process_payload_policy
            .policy
            .is_forced(ForceName::EnableExportAddressFilterPlus)
    }

    pub fn set_override_enable_export_address_filter_plus(&mut self, value: bool) {
        self.process_payload_policy
            .policy
            .set_force(ForceName::EnableExportAddressFilterPlus, value);
    }

    pub fn override_enable_import_address_filter(&self) -> bool {
        self.process_payload_policy
            .policy
            .is_forced(ForceName::EnableImportAddressFilter)
    }

    pub fn set_override_enable_import_address_filter(&mut self, value: bool) {
        self.process_payload_policy
            .policy
            .set_force(ForceName::EnableImportAddressFilter, value);
    }

    pub fn override_enable_rop_stack_pivot(&self) -> bool {
        self.process_payload_policy
            .policy
            .is_forced(ForceName::EnableRopStackPivot)
    }

    pub fn set_override_enable_rop_stack_pivot(&mut self, value: bool) {
        self.process_payload_policy
            .policy
            .set_force(ForceName::EnableRopStackPivot, value);
    }

    pub fn override_enable_rop_caller_check(&self) -> bool {
        self.process_payload_policy
            .policy
            .is_forced(ForceName::EnableRopCallerCheck)
    }

    pub fn set_override_enable_rop_caller_check(&mut self, value: bool) {
        self.process_payload_policy
            .policy
            .set_force(ForceName::EnableRopCallerCheck, value);
    }

    pub fn override_enable_rop_sim_exec(&self) -> bool {
        self.process_payload_policy
            .policy
            .is_forced(ForceName::EnableRopSimExec)
    }

    pub fn set_override_enable_rop_sim_exec(&mut self, value: bool) {
        self.process_payload_policy
            .policy
            .set_force(ForceName::EnableRopSimExec, value);
    }

    pub fn enable_export_address_filter(&self) -> OptionValue {
        self.process_payload_policy.enable_export_address_filter()
    }

    pub fn set_enable_export_address_filter(&mut self, value: OptionValue) {
        self.process_payload_policy
            .set_enable_export_address_filter(value);
    }

    pub fn audit_enable_export_address_filter(&self) -> OptionValue {
        self.process_payload_policy
            .audit_enable_export_address_filter()
    }

    pub fn set_audit_enable_export_address_filter(&mut self, value: OptionValue) {
        self.process_payload_policy
            .set_audit_enable_export_address_filter(value);
    }

    pub fn enable_export_address_filter_plus(&self) -> OptionValue {
        self.process_payload_policy
            .enable_export_address_filter_plus()
    }

    pub fn set_enable_export_address_filter_plus(&mut self, value: OptionValue) {
        self.process_payload_policy
            .set_enable_export_address_filter_plus(value);
    }

    pub fn audit_enable_export_address_filter_plus(&self) -> OptionValue {
        self.process_payload_policy
            .audit_enable_export_address_filter_plus()
    }

    pub fn set_audit_enable_export_address_filter_plus(&mut self, value: OptionValue) {
        self.process_payload_policy
            .set_audit_enable_export_address_filter_plus(value);
    }

    pub fn enable_import_address_filter(&self) -> OptionValue {
        self.process_payload_policy.enable_import_address_filter()
    }

    pub fn set_enable_import_address_filter(&mut self, value: OptionValue) {
        self.process_payload_policy
            .set_enable_import_address_filter(value);
    }

    pub fn audit_enable_import_address_filter(&self) -> OptionValue {
        self.process_payload_policy
            .audit_enable_import_address_filter()
    }

    pub fn set_audit_enable_import_address_filter(&mut self, value: OptionValue) {
        self.process_payload_policy
            .set_audit_enable_import_address_filter(value);
    }

    pub fn enable_rop_stack_pivot(&self) -> OptionValue {
        self.process_payload_policy.enable_rop_stack_pivot()
    }

    pub fn set_enable_rop_stack_pivot(&mut self, value: OptionValue) {
        self.process_payload_policy
            .set_enable_rop_stack_pivot(value);
    }

    pub fn audit_enable_rop_stack_pivot(&self) -> OptionValue {
        self.process_payload_policy.audit_enable_rop_stack_pivot()
    }

    pub fn set_audit_enable_rop_stack_pivot(&mut self, value: OptionValue) {
        self.process_payload_policy
            .set_audit_enable_rop_stack_pivot(value);
    }

    pub fn enable_rop_caller_check(&self) -> OptionValue {
        self.process_payload_policy.enable_rop_caller_check()
    }

    pub fn set_enable_rop_caller_check(&mut self, value: OptionValue) {
        self.process_payload_policy
            .set_enable_rop_caller_check(value);
    }

    pub fn audit_enable_rop_caller_check(&self) -> OptionValue {
        self.process_payload_policy.audit_enable_rop_caller_check()
    }

    pub fn set_audit_enable_rop_caller_check(&mut self, value: OptionValue) {
        self.process_payload_policy
            .set_audit_enable_rop_caller_check(value);
    }

    pub fn enable_rop_sim_exec(&self) -> OptionValue {
        self.process_payload_policy.enable_rop_sim_exec()
    }

    pub fn set_enable_rop_sim_exec(&mut self, value: OptionValue) {
        self.process_payload_policy.set_enable_rop_sim_exec(value);
    }

    pub fn audit_enable_rop_sim_exec(&self) -> OptionValue {
        self.process_payload_policy.audit_enable_rop_sim_exec()
    }

    pub fn set_audit_enable_rop_sim_exec(&mut self, value: OptionValue) {
        self.process_payload_policy
            .set_audit_enable_rop_sim_exec(value);
    }

    pub fn flags(&self) -> u32 {
        self.process_payload_policy.flags()
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.process_payload_policy.set_flags(flags);
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.process_payload_policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.process_payload_policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.process_payload_policy.set_policy(name, value);
    }
}

// ProcessChildProcessPolicy
#[derive(Debug, Clone)]
pub struct ProcessChildProcessPolicy {
    policy: Policy,
}

impl ProcessChildProcessPolicy {
    pub fn new() -> Self {
        let mut policy = Policy::new();
        policy.add(PolicyOptionName::DisallowChildProcessCreation, false);
        policy.add(PolicyOptionName::Audit, false);
        Self { policy }
    }

    pub fn disallow_child_process_creation(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::DisallowChildProcessCreation)
    }

    pub fn set_disallow_child_process_creation(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::DisallowChildProcessCreation, value);
    }

    pub fn audit(&self) -> OptionValue {
        self.policy.get_policy(PolicyOptionName::Audit)
    }

    pub fn set_audit(&mut self, value: OptionValue) {
        self.policy.set_policy(PolicyOptionName::Audit, value);
    }

    pub fn flags(&self) -> u32 {
        self.policy.flags
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.policy.flags = flags;
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.policy.set_policy(name, value);
    }
}

// ChildProcessPolicy
#[derive(Debug, Clone)]
pub struct ChildProcessPolicy {
    process_child_process_policy: ProcessChildProcessPolicy,
}

impl ChildProcessPolicy {
    pub fn new() -> Self {
        let mut policy = ProcessChildProcessPolicy::new();
        policy
            .policy
            .force_names
            .insert(ForceName::ChildProcess, false);
        Self {
            process_child_process_policy: policy,
        }
    }

    pub fn override_child_process(&self) -> bool {
        self.process_child_process_policy
            .policy
            .is_forced(ForceName::ChildProcess)
    }

    pub fn set_override_child_process(&mut self, value: bool) {
        self.process_child_process_policy
            .policy
            .set_force(ForceName::ChildProcess, value);
    }

    pub fn disallow_child_process_creation(&self) -> OptionValue {
        self.process_child_process_policy
            .disallow_child_process_creation()
    }

    pub fn set_disallow_child_process_creation(&mut self, value: OptionValue) {
        self.process_child_process_policy
            .set_disallow_child_process_creation(value);
    }

    pub fn audit(&self) -> OptionValue {
        self.process_child_process_policy.audit()
    }

    pub fn set_audit(&mut self, value: OptionValue) {
        self.process_child_process_policy.set_audit(value);
    }

    pub fn flags(&self) -> u32 {
        self.process_child_process_policy.flags()
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.process_child_process_policy.set_flags(flags);
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.process_child_process_policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.process_child_process_policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.process_child_process_policy.set_policy(name, value);
    }
}

// ProcessUserShadowStackPolicy
#[derive(Debug, Clone)]
pub struct ProcessUserShadowStackPolicy {
    policy: Policy,
}

impl ProcessUserShadowStackPolicy {
    pub fn new() -> Self {
        let mut policy = Policy::new();
        policy.add(PolicyOptionName::UserShadowStack, false);
        policy.add(PolicyOptionName::UserShadowStackStrictMode, false);
        policy.add(PolicyOptionName::AuditUserShadowStack, false);
        policy.add(PolicyOptionName::SetContextIpValidation, false);
        policy.add(PolicyOptionName::AuditSetContextIpValidation, false);
        policy.add(PolicyOptionName::BlockNonCetBinaries, false);
        policy.add(PolicyOptionName::BlockNonCetBinariesNonEhcont, false);
        policy.add(PolicyOptionName::AuditBlockNonCetBinaries, false);
        Self { policy }
    }

    pub fn user_shadow_stack(&self) -> OptionValue {
        self.policy.get_policy(PolicyOptionName::UserShadowStack)
    }

    pub fn set_user_shadow_stack(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::UserShadowStack, value);
    }

    pub fn user_shadow_stack_strict_mode(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::UserShadowStackStrictMode)
    }

    pub fn set_user_shadow_stack_strict_mode(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::UserShadowStackStrictMode, value);
    }

    pub fn audit_user_shadow_stack(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::AuditUserShadowStack)
    }

    pub fn set_audit_user_shadow_stack(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::AuditUserShadowStack, value);
    }

    pub fn set_context_ip_validation(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::SetContextIpValidation)
    }

    pub fn set_set_context_ip_validation(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::SetContextIpValidation, value);
    }

    pub fn audit_set_context_ip_validation(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::AuditSetContextIpValidation)
    }

    pub fn set_audit_set_context_ip_validation(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::AuditSetContextIpValidation, value);
    }

    pub fn block_non_cet_binaries(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::BlockNonCetBinaries)
    }

    pub fn set_block_non_cet_binaries(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::BlockNonCetBinaries, value);
    }

    pub fn block_non_cet_binaries_non_ehcont(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::BlockNonCetBinariesNonEhcont)
    }

    pub fn set_block_non_cet_binaries_non_ehcont(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::BlockNonCetBinariesNonEhcont, value);
    }

    pub fn audit_block_non_cet_binaries(&self) -> OptionValue {
        self.policy
            .get_policy(PolicyOptionName::AuditBlockNonCetBinaries)
    }

    pub fn set_audit_block_non_cet_binaries(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::AuditBlockNonCetBinaries, value);
    }

    pub fn flags(&self) -> u32 {
        self.policy.flags
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.policy.flags = flags;
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.policy.set_policy(name, value);
    }
}

// UserShadowStackPolicy
#[derive(Debug, Clone)]
pub struct UserShadowStackPolicy {
    process_user_shadow_stack_policy: ProcessUserShadowStackPolicy,
}

impl UserShadowStackPolicy {
    pub fn new() -> Self {
        let mut policy = ProcessUserShadowStackPolicy::new();
        policy
            .policy
            .force_names
            .insert(ForceName::UserShadowStack, false);
        Self {
            process_user_shadow_stack_policy: policy,
        }
    }

    pub fn override_user_shadow_stack(&self) -> bool {
        self.process_user_shadow_stack_policy
            .policy
            .is_forced(ForceName::UserShadowStack)
    }

    pub fn set_override_user_shadow_stack(&mut self, value: bool) {
        self.process_user_shadow_stack_policy
            .policy
            .set_force(ForceName::UserShadowStack, value);
    }

    pub fn user_shadow_stack(&self) -> OptionValue {
        self.process_user_shadow_stack_policy.user_shadow_stack()
    }

    pub fn set_user_shadow_stack(&mut self, value: OptionValue) {
        self.process_user_shadow_stack_policy
            .set_user_shadow_stack(value);
    }

    pub fn user_shadow_stack_strict_mode(&self) -> OptionValue {
        self.process_user_shadow_stack_policy
            .user_shadow_stack_strict_mode()
    }

    pub fn set_user_shadow_stack_strict_mode(&mut self, value: OptionValue) {
        self.process_user_shadow_stack_policy
            .set_user_shadow_stack_strict_mode(value);
    }

    pub fn audit_user_shadow_stack(&self) -> OptionValue {
        self.process_user_shadow_stack_policy
            .audit_user_shadow_stack()
    }

    pub fn set_audit_user_shadow_stack(&mut self, value: OptionValue) {
        self.process_user_shadow_stack_policy
            .set_audit_user_shadow_stack(value);
    }

    pub fn set_context_ip_validation(&self) -> OptionValue {
        self.process_user_shadow_stack_policy
            .set_context_ip_validation()
    }

    pub fn set_set_context_ip_validation(&mut self, value: OptionValue) {
        self.process_user_shadow_stack_policy
            .set_set_context_ip_validation(value);
    }

    pub fn audit_set_context_ip_validation(&self) -> OptionValue {
        self.process_user_shadow_stack_policy
            .audit_set_context_ip_validation()
    }

    pub fn set_audit_set_context_ip_validation(&mut self, value: OptionValue) {
        self.process_user_shadow_stack_policy
            .set_audit_set_context_ip_validation(value);
    }

    pub fn block_non_cet_binaries(&self) -> OptionValue {
        self.process_user_shadow_stack_policy
            .block_non_cet_binaries()
    }

    pub fn set_block_non_cet_binaries(&mut self, value: OptionValue) {
        self.process_user_shadow_stack_policy
            .set_block_non_cet_binaries(value);
    }

    pub fn block_non_cet_binaries_non_ehcont(&self) -> OptionValue {
        self.process_user_shadow_stack_policy
            .block_non_cet_binaries_non_ehcont()
    }

    pub fn set_block_non_cet_binaries_non_ehcont(&mut self, value: OptionValue) {
        self.process_user_shadow_stack_policy
            .set_block_non_cet_binaries_non_ehcont(value);
    }

    pub fn audit_block_non_cet_binaries(&self) -> OptionValue {
        self.process_user_shadow_stack_policy
            .audit_block_non_cet_binaries()
    }

    pub fn set_audit_block_non_cet_binaries(&mut self, value: OptionValue) {
        self.process_user_shadow_stack_policy
            .set_audit_block_non_cet_binaries(value);
    }

    pub fn flags(&self) -> u32 {
        self.process_user_shadow_stack_policy.flags()
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.process_user_shadow_stack_policy.set_flags(flags);
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.process_user_shadow_stack_policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.process_user_shadow_stack_policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.process_user_shadow_stack_policy
            .set_policy(name, value);
    }
}

// ProcessSEHOPPolicy
#[derive(Debug, Clone)]
pub struct ProcessSEHOPPolicy {
    policy: Policy,
}

impl ProcessSEHOPPolicy {
    pub fn new() -> Self {
        let mut policy = Policy::new();
        policy.add(PolicyOptionName::Enable, false);
        policy.add(PolicyOptionName::TelemetryOnly, false);
        policy.add(PolicyOptionName::Audit, false);
        policy.force_names.insert(ForceName::SEHOP, false);
        Self { policy }
    }

    pub fn enable(&self) -> OptionValue {
        self.policy.get_policy(PolicyOptionName::Enable)
    }

    pub fn set_enable(&mut self, value: OptionValue) {
        self.policy.set_policy(PolicyOptionName::Enable, value);
    }

    pub fn telemetry_only(&self) -> OptionValue {
        self.policy.get_policy(PolicyOptionName::TelemetryOnly)
    }

    pub fn set_telemetry_only(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::TelemetryOnly, value);
    }

    pub fn audit(&self) -> OptionValue {
        self.policy.get_policy(PolicyOptionName::Audit)
    }

    pub fn set_audit(&mut self, value: OptionValue) {
        self.policy.set_policy(PolicyOptionName::Audit, value);
    }

    pub fn flags(&self) -> u32 {
        self.policy.flags
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.policy.flags = flags;
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.policy.set_policy(name, value);
    }
}

// SEHOPPolicy
#[derive(Debug, Clone)]
pub struct SEHOPPolicy {
    process_sehop_policy: ProcessSEHOPPolicy,
}

impl SEHOPPolicy {
    pub fn new() -> Self {
        let policy = ProcessSEHOPPolicy::new();
        Self {
            process_sehop_policy: policy,
        }
    }

    pub fn override_sehop(&self) -> bool {
        self.process_sehop_policy.policy.is_forced(ForceName::SEHOP)
    }

    pub fn set_override_sehop(&mut self, value: bool) {
        self.process_sehop_policy
            .policy
            .set_force(ForceName::SEHOP, value);
    }

    pub fn enable(&self) -> OptionValue {
        self.process_sehop_policy.enable()
    }

    pub fn set_enable(&mut self, value: OptionValue) {
        self.process_sehop_policy.set_enable(value);
    }

    pub fn telemetry_only(&self) -> OptionValue {
        self.process_sehop_policy.telemetry_only()
    }

    pub fn set_telemetry_only(&mut self, value: OptionValue) {
        self.process_sehop_policy.set_telemetry_only(value);
    }

    pub fn audit(&self) -> OptionValue {
        self.process_sehop_policy.audit()
    }

    pub fn set_audit(&mut self, value: OptionValue) {
        self.process_sehop_policy.set_audit(value);
    }

    pub fn flags(&self) -> u32 {
        self.process_sehop_policy.flags()
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.process_sehop_policy.set_flags(flags);
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.process_sehop_policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.process_sehop_policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.process_sehop_policy.set_policy(name, value);
    }
}

// HeapPolicy
#[derive(Debug, Clone)]
pub struct HeapPolicy {
    policy: Policy,
}

impl HeapPolicy {
    pub fn new() -> Self {
        let mut policy = Policy::new();
        policy.add(PolicyOptionName::TerminateOnError, false);
        policy.force_names.insert(ForceName::Heap, false);
        Self { policy }
    }

    pub fn terminate_on_error(&self) -> OptionValue {
        self.policy.get_policy(PolicyOptionName::TerminateOnError)
    }

    pub fn set_terminate_on_error(&mut self, value: OptionValue) {
        self.policy
            .set_policy(PolicyOptionName::TerminateOnError, value);
    }

    pub fn override_heap(&self) -> bool {
        self.policy.is_forced(ForceName::Heap)
    }

    pub fn set_override_heap(&mut self, value: bool) {
        self.policy.set_force(ForceName::Heap, value);
    }

    pub fn flags(&self) -> u32 {
        self.policy.flags
    }

    pub fn set_flags(&mut self, flags: u32) {
        self.policy.flags = flags;
    }

    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        self.policy.get_all_options()
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        self.policy.get_policy(name)
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        self.policy.set_policy(name, value);
    }
}

#[derive(Debug, Clone)]
pub struct ProcessMitigations {
    pub process_name: String,
    pub source: String,
    pub id: u32,
    pub policies: HashMap<PolicyName, PolicyContainer>,
}

#[derive(Debug, Clone)]
pub enum PolicyContainer {
    Dep(ProcessDEPPolicy),
    Aslr(ProcessASLRPolicy),
    StrictHandle(ProcessStrictHandlePolicy),
    SystemCalls(ProcessSystemCallPolicy),
    ExtensionPoints(ProcessExtensionPointPolicy),
    DynamicCode(ProcessDynamicCodePolicy),
    ControlFlowGuard(ProcessCFGPolicy),
    SignedBinaries(ProcessBinarySignaturePolicy),
    Fonts(ProcessFontDisablePolicy),
    ImageLoad(ProcessImageLoadPolicy),
    Payload(ProcessPayloadPolicy),
    ChildProcess(ProcessChildProcessPolicy),
    UserShadowStack(ProcessUserShadowStackPolicy),
    SEHOP(ProcessSEHOPPolicy),
}

impl PolicyContainer {
    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        match self {
            PolicyContainer::Dep(p) => p.get_all_options(),
            PolicyContainer::Aslr(p) => p.get_all_options(),
            PolicyContainer::StrictHandle(p) => p.get_all_options(),
            PolicyContainer::SystemCalls(p) => p.get_all_options(),
            PolicyContainer::ExtensionPoints(p) => p.get_all_options(),
            PolicyContainer::DynamicCode(p) => p.get_all_options(),
            PolicyContainer::ControlFlowGuard(p) => p.get_all_options(),
            PolicyContainer::SignedBinaries(p) => p.get_all_options(),
            PolicyContainer::Fonts(p) => p.get_all_options(),
            PolicyContainer::ImageLoad(p) => p.get_all_options(),
            PolicyContainer::Payload(p) => p.get_all_options(),
            PolicyContainer::ChildProcess(p) => p.get_all_options(),
            PolicyContainer::UserShadowStack(p) => p.get_all_options(),
            PolicyContainer::SEHOP(p) => p.get_all_options(),
        }
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        match self {
            PolicyContainer::Dep(p) => p.get_policy(name),
            PolicyContainer::Aslr(p) => p.get_policy(name),
            PolicyContainer::StrictHandle(p) => p.get_policy(name),
            PolicyContainer::SystemCalls(p) => p.get_policy(name),
            PolicyContainer::ExtensionPoints(p) => p.get_policy(name),
            PolicyContainer::DynamicCode(p) => p.get_policy(name),
            PolicyContainer::ControlFlowGuard(p) => p.get_policy(name),
            PolicyContainer::SignedBinaries(p) => p.get_policy(name),
            PolicyContainer::Fonts(p) => p.get_policy(name),
            PolicyContainer::ImageLoad(p) => p.get_policy(name),
            PolicyContainer::Payload(p) => p.get_policy(name),
            PolicyContainer::ChildProcess(p) => p.get_policy(name),
            PolicyContainer::UserShadowStack(p) => p.get_policy(name),
            PolicyContainer::SEHOP(p) => p.get_policy(name),
        }
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        match self {
            PolicyContainer::Dep(p) => p.set_policy(name, value),
            PolicyContainer::Aslr(p) => p.set_policy(name, value),
            PolicyContainer::StrictHandle(p) => p.set_policy(name, value),
            PolicyContainer::SystemCalls(p) => p.set_policy(name, value),
            PolicyContainer::ExtensionPoints(p) => p.set_policy(name, value),
            PolicyContainer::DynamicCode(p) => p.set_policy(name, value),
            PolicyContainer::ControlFlowGuard(p) => p.set_policy(name, value),
            PolicyContainer::SignedBinaries(p) => p.set_policy(name, value),
            PolicyContainer::Fonts(p) => p.set_policy(name, value),
            PolicyContainer::ImageLoad(p) => p.set_policy(name, value),
            PolicyContainer::Payload(p) => p.set_policy(name, value),
            PolicyContainer::ChildProcess(p) => p.set_policy(name, value),
            PolicyContainer::UserShadowStack(p) => p.set_policy(name, value),
            PolicyContainer::SEHOP(p) => p.set_policy(name, value),
        }
    }
}

impl ProcessMitigations {
    pub fn new(name: &str) -> Self {
        let mut policies: HashMap<PolicyName, PolicyContainer> = HashMap::new();

        policies.insert(
            PolicyName::DEP,
            PolicyContainer::Dep(ProcessDEPPolicy::new()),
        );
        policies.insert(
            PolicyName::ASLR,
            PolicyContainer::Aslr(ProcessASLRPolicy::new()),
        );
        policies.insert(
            PolicyName::StrictHandle,
            PolicyContainer::StrictHandle(ProcessStrictHandlePolicy::new()),
        );
        policies.insert(
            PolicyName::SystemCalls,
            PolicyContainer::SystemCalls(ProcessSystemCallPolicy::new()),
        );
        policies.insert(
            PolicyName::ExtensionPoints,
            PolicyContainer::ExtensionPoints(ProcessExtensionPointPolicy::new()),
        );
        policies.insert(
            PolicyName::DynamicCode,
            PolicyContainer::DynamicCode(ProcessDynamicCodePolicy::new()),
        );
        policies.insert(
            PolicyName::ControlFlowGuard,
            PolicyContainer::ControlFlowGuard(ProcessCFGPolicy::new()),
        );
        policies.insert(
            PolicyName::SignedBinaries,
            PolicyContainer::SignedBinaries(ProcessBinarySignaturePolicy::new()),
        );
        policies.insert(
            PolicyName::Fonts,
            PolicyContainer::Fonts(ProcessFontDisablePolicy::new()),
        );
        policies.insert(
            PolicyName::ImageLoad,
            PolicyContainer::ImageLoad(ProcessImageLoadPolicy::new()),
        );
        policies.insert(
            PolicyName::Payload,
            PolicyContainer::Payload(ProcessPayloadPolicy::new()),
        );
        policies.insert(
            PolicyName::ChildProcess,
            PolicyContainer::ChildProcess(ProcessChildProcessPolicy::new()),
        );
        policies.insert(
            PolicyName::UserShadowStack,
            PolicyContainer::UserShadowStack(ProcessUserShadowStackPolicy::new()),
        );
        policies.insert(
            PolicyName::SEHOP,
            PolicyContainer::SEHOP(ProcessSEHOPPolicy::new()),
        );

        Self {
            process_name: name.to_string(),
            source: "None".to_string(),
            id: 0,
            policies,
        }
    }

    pub fn new_from_copy(mitigations: &ProcessMitigations) -> Self {
        let mut new_mitigations =
            Self::new_with_default(&mitigations.process_name, Some(mitigations));
        new_mitigations.source = mitigations.source.clone();
        new_mitigations.id = mitigations.id;
        new_mitigations
    }

    pub fn new_with_default(name: &str, default_mitigations: Option<&ProcessMitigations>) -> Self {
        let mut mitigations = Self::new(name);

        if let Some(default_mits) = default_mitigations {
            let policy_names: Vec<PolicyName> = mitigations.policies.keys().copied().collect();
            for policy_name in policy_names {
                let all_options = mitigations.policies[&policy_name].get_all_options();
                for option in all_options {
                    if let Some(default_policy) = default_mits.policies.get(&policy_name) {
                        let value = default_policy.get_policy(option);
                        if let Some(policy) = mitigations.policies.get_mut(&policy_name) {
                            policy.set_policy(option, value);
                        }
                    }
                }
            }
        }

        mitigations
    }

    pub fn set_policy(&mut self, name: PolicyName, policy_container: PolicyContainer) {
        if let Some(existing_policy) = self.policies.get_mut(&name) {
            for option in existing_policy.get_all_options() {
                let value = policy_container.get_policy(option);
                existing_policy.set_policy(option, value);
            }
        }
    }

    pub fn dep(&self) -> Option<&ProcessDEPPolicy> {
        if let Some(PolicyContainer::Dep(policy)) = self.policies.get(&PolicyName::DEP) {
            Some(policy)
        } else {
            None
        }
    }

    pub fn aslr(&self) -> Option<&ProcessASLRPolicy> {
        if let Some(PolicyContainer::Aslr(policy)) = self.policies.get(&PolicyName::ASLR) {
            Some(policy)
        } else {
            None
        }
    }

    pub fn strict_handle(&self) -> Option<&ProcessStrictHandlePolicy> {
        if let Some(PolicyContainer::StrictHandle(policy)) =
            self.policies.get(&PolicyName::StrictHandle)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn system_call(&self) -> Option<&ProcessSystemCallPolicy> {
        if let Some(PolicyContainer::SystemCalls(policy)) =
            self.policies.get(&PolicyName::SystemCalls)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn extension_point(&self) -> Option<&ProcessExtensionPointPolicy> {
        if let Some(PolicyContainer::ExtensionPoints(policy)) =
            self.policies.get(&PolicyName::ExtensionPoints)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn dynamic_code(&self) -> Option<&ProcessDynamicCodePolicy> {
        if let Some(PolicyContainer::DynamicCode(policy)) =
            self.policies.get(&PolicyName::DynamicCode)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn cfg(&self) -> Option<&ProcessCFGPolicy> {
        if let Some(PolicyContainer::ControlFlowGuard(policy)) =
            self.policies.get(&PolicyName::ControlFlowGuard)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn binary_signature(&self) -> Option<&ProcessBinarySignaturePolicy> {
        if let Some(PolicyContainer::SignedBinaries(policy)) =
            self.policies.get(&PolicyName::SignedBinaries)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn font_disable(&self) -> Option<&ProcessFontDisablePolicy> {
        if let Some(PolicyContainer::Fonts(policy)) = self.policies.get(&PolicyName::Fonts) {
            Some(policy)
        } else {
            None
        }
    }

    pub fn image_load(&self) -> Option<&ProcessImageLoadPolicy> {
        if let Some(PolicyContainer::ImageLoad(policy)) = self.policies.get(&PolicyName::ImageLoad)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn payload(&self) -> Option<&ProcessPayloadPolicy> {
        if let Some(PolicyContainer::Payload(policy)) = self.policies.get(&PolicyName::Payload) {
            Some(policy)
        } else {
            None
        }
    }

    pub fn child_process(&self) -> Option<&ProcessChildProcessPolicy> {
        if let Some(PolicyContainer::ChildProcess(policy)) =
            self.policies.get(&PolicyName::ChildProcess)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn user_shadow_stack(&self) -> Option<&ProcessUserShadowStackPolicy> {
        if let Some(PolicyContainer::UserShadowStack(policy)) =
            self.policies.get(&PolicyName::UserShadowStack)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn sehop(&self) -> Option<&ProcessSEHOPPolicy> {
        if let Some(PolicyContainer::SEHOP(policy)) = self.policies.get(&PolicyName::SEHOP) {
            Some(policy)
        } else {
            None
        }
    }
}

impl fmt::Display for ProcessMitigations {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        writeln!(f, "Process:\t{}", self.process_name)?;
        writeln!(f, "Source: \t{}", self.source)?;
        let _is_registry = self.source != "Registry";
        for (policy_name, policy) in &self.policies {
            writeln!(f, "{:?}: {:?}", policy_name, policy)?;
        }
        Ok(())
    }
}

#[derive(Debug, Clone)]
pub struct AppMitigations {
    pub process_name: String,
    pub source: String,
    pub policies: HashMap<PolicyName, AppPolicyContainer>,
}

#[derive(Debug, Clone)]
pub enum AppPolicyContainer {
    Dep(DEPPolicy),
    Aslr(ASLRPolicy),
    StrictHandle(StrictHandlePolicy),
    SystemCalls(SystemCallPolicy),
    ExtensionPoints(ExtensionPointPolicy),
    DynamicCode(DynamicCodePolicy),
    ControlFlowGuard(CFGPolicy),
    SignedBinaries(BinarySignaturePolicy),
    Fonts(FontDisablePolicy),
    ImageLoad(ImageLoadPolicy),
    Payload(PayloadPolicy),
    ChildProcess(ChildProcessPolicy),
    UserShadowStack(UserShadowStackPolicy),
    SEHOP(SEHOPPolicy),
    Heap(HeapPolicy),
}

impl AppPolicyContainer {
    pub fn get_all_options(&self) -> Vec<PolicyOptionName> {
        match self {
            AppPolicyContainer::Dep(p) => p.get_all_options(),
            AppPolicyContainer::Aslr(p) => p.get_all_options(),
            AppPolicyContainer::StrictHandle(p) => p.get_all_options(),
            AppPolicyContainer::SystemCalls(p) => p.get_all_options(),
            AppPolicyContainer::ExtensionPoints(p) => p.get_all_options(),
            AppPolicyContainer::DynamicCode(p) => p.get_all_options(),
            AppPolicyContainer::ControlFlowGuard(p) => p.get_all_options(),
            AppPolicyContainer::SignedBinaries(p) => p.get_all_options(),
            AppPolicyContainer::Fonts(p) => p.get_all_options(),
            AppPolicyContainer::ImageLoad(p) => p.get_all_options(),
            AppPolicyContainer::Payload(p) => p.get_all_options(),
            AppPolicyContainer::ChildProcess(p) => p.get_all_options(),
            AppPolicyContainer::UserShadowStack(p) => p.get_all_options(),
            AppPolicyContainer::SEHOP(p) => p.get_all_options(),
            AppPolicyContainer::Heap(p) => p.get_all_options(),
        }
    }

    pub fn get_policy(&self, name: PolicyOptionName) -> OptionValue {
        match self {
            AppPolicyContainer::Dep(p) => p.get_policy(name),
            AppPolicyContainer::Aslr(p) => p.get_policy(name),
            AppPolicyContainer::StrictHandle(p) => p.get_policy(name),
            AppPolicyContainer::SystemCalls(p) => p.get_policy(name),
            AppPolicyContainer::ExtensionPoints(p) => p.get_policy(name),
            AppPolicyContainer::DynamicCode(p) => p.get_policy(name),
            AppPolicyContainer::ControlFlowGuard(p) => p.get_policy(name),
            AppPolicyContainer::SignedBinaries(p) => p.get_policy(name),
            AppPolicyContainer::Fonts(p) => p.get_policy(name),
            AppPolicyContainer::ImageLoad(p) => p.get_policy(name),
            AppPolicyContainer::Payload(p) => p.get_policy(name),
            AppPolicyContainer::ChildProcess(p) => p.get_policy(name),
            AppPolicyContainer::UserShadowStack(p) => p.get_policy(name),
            AppPolicyContainer::SEHOP(p) => p.get_policy(name),
            AppPolicyContainer::Heap(p) => p.get_policy(name),
        }
    }

    pub fn set_policy(&mut self, name: PolicyOptionName, value: OptionValue) {
        match self {
            AppPolicyContainer::Dep(p) => p.set_policy(name, value),
            AppPolicyContainer::Aslr(p) => p.set_policy(name, value),
            AppPolicyContainer::StrictHandle(p) => p.set_policy(name, value),
            AppPolicyContainer::SystemCalls(p) => p.set_policy(name, value),
            AppPolicyContainer::ExtensionPoints(p) => p.set_policy(name, value),
            AppPolicyContainer::DynamicCode(p) => p.set_policy(name, value),
            AppPolicyContainer::ControlFlowGuard(p) => p.set_policy(name, value),
            AppPolicyContainer::SignedBinaries(p) => p.set_policy(name, value),
            AppPolicyContainer::Fonts(p) => p.set_policy(name, value),
            AppPolicyContainer::ImageLoad(p) => p.set_policy(name, value),
            AppPolicyContainer::Payload(p) => p.set_policy(name, value),
            AppPolicyContainer::ChildProcess(p) => p.set_policy(name, value),
            AppPolicyContainer::UserShadowStack(p) => p.set_policy(name, value),
            AppPolicyContainer::SEHOP(p) => p.set_policy(name, value),
            AppPolicyContainer::Heap(p) => p.set_policy(name, value),
        }
    }
}

impl AppMitigations {
    pub fn new(name: &str) -> Self {
        let mut policies: HashMap<PolicyName, AppPolicyContainer> = HashMap::new();

        policies.insert(PolicyName::DEP, AppPolicyContainer::Dep(DEPPolicy::new()));
        policies.insert(
            PolicyName::ASLR,
            AppPolicyContainer::Aslr(ASLRPolicy::new()),
        );
        policies.insert(
            PolicyName::StrictHandle,
            AppPolicyContainer::StrictHandle(StrictHandlePolicy::new()),
        );
        policies.insert(
            PolicyName::SystemCalls,
            AppPolicyContainer::SystemCalls(SystemCallPolicy::new()),
        );
        policies.insert(
            PolicyName::ExtensionPoints,
            AppPolicyContainer::ExtensionPoints(ExtensionPointPolicy::new()),
        );
        policies.insert(
            PolicyName::DynamicCode,
            AppPolicyContainer::DynamicCode(DynamicCodePolicy::new()),
        );
        policies.insert(
            PolicyName::ControlFlowGuard,
            AppPolicyContainer::ControlFlowGuard(CFGPolicy::new()),
        );
        policies.insert(
            PolicyName::SignedBinaries,
            AppPolicyContainer::SignedBinaries(BinarySignaturePolicy::new()),
        );
        policies.insert(
            PolicyName::Fonts,
            AppPolicyContainer::Fonts(FontDisablePolicy::new()),
        );
        policies.insert(
            PolicyName::ImageLoad,
            AppPolicyContainer::ImageLoad(ImageLoadPolicy::new()),
        );
        policies.insert(
            PolicyName::Payload,
            AppPolicyContainer::Payload(PayloadPolicy::new()),
        );
        policies.insert(
            PolicyName::SEHOP,
            AppPolicyContainer::SEHOP(SEHOPPolicy::new()),
        );
        policies.insert(
            PolicyName::Heap,
            AppPolicyContainer::Heap(HeapPolicy::new()),
        );
        policies.insert(
            PolicyName::ChildProcess,
            AppPolicyContainer::ChildProcess(ChildProcessPolicy::new()),
        );
        policies.insert(
            PolicyName::UserShadowStack,
            AppPolicyContainer::UserShadowStack(UserShadowStackPolicy::new()),
        );

        Self {
            process_name: name.to_string(),
            source: "None".to_string(),
            policies,
        }
    }

    pub fn new_from_copy(app_mitigations: &AppMitigations) -> Self {
        let mut new_mitigations =
            Self::new_with_default(&app_mitigations.process_name, Some(app_mitigations));
        new_mitigations.source = app_mitigations.source.clone();
        new_mitigations
    }

    pub fn new_with_default(name: &str, default_mitigations: Option<&AppMitigations>) -> Self {
        let mut mitigations = Self::new(name);

        if let Some(default_mits) = default_mitigations {
            mitigations.source = default_mits.source.clone();

            let policy_names: Vec<PolicyName> = mitigations.policies.keys().copied().collect();
            for policy_name in policy_names {
                let all_options = mitigations.policies[&policy_name].get_all_options();
                for option in all_options {
                    if let Some(default_policy) = default_mits.policies.get(&policy_name) {
                        let value = default_policy.get_policy(option);
                        if let Some(policy) = mitigations.policies.get_mut(&policy_name) {
                            policy.set_policy(option, value);
                        }
                    }
                }
            }
        }

        mitigations
    }

    pub fn set_policy(&mut self, name: PolicyName, policy_container: AppPolicyContainer) {
        if let Some(existing_policy) = self.policies.get_mut(&name) {
            for option in existing_policy.get_all_options() {
                let value = policy_container.get_policy(option);
                existing_policy.set_policy(option, value);
            }
        }
    }

    pub fn dep(&self) -> Option<&DEPPolicy> {
        if let Some(AppPolicyContainer::Dep(policy)) = self.policies.get(&PolicyName::DEP) {
            Some(policy)
        } else {
            None
        }
    }

    pub fn dep_mut(&mut self) -> Option<&mut DEPPolicy> {
        if let Some(AppPolicyContainer::Dep(policy)) = self.policies.get_mut(&PolicyName::DEP) {
            Some(policy)
        } else {
            None
        }
    }

    pub fn aslr(&self) -> Option<&ASLRPolicy> {
        if let Some(AppPolicyContainer::Aslr(policy)) = self.policies.get(&PolicyName::ASLR) {
            Some(policy)
        } else {
            None
        }
    }

    pub fn aslr_mut(&mut self) -> Option<&mut ASLRPolicy> {
        if let Some(AppPolicyContainer::Aslr(policy)) = self.policies.get_mut(&PolicyName::ASLR) {
            Some(policy)
        } else {
            None
        }
    }

    pub fn strict_handle(&self) -> Option<&StrictHandlePolicy> {
        if let Some(AppPolicyContainer::StrictHandle(policy)) =
            self.policies.get(&PolicyName::StrictHandle)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn strict_handle_mut(&mut self) -> Option<&mut StrictHandlePolicy> {
        if let Some(AppPolicyContainer::StrictHandle(policy)) =
            self.policies.get_mut(&PolicyName::StrictHandle)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn system_call(&self) -> Option<&SystemCallPolicy> {
        if let Some(AppPolicyContainer::SystemCalls(policy)) =
            self.policies.get(&PolicyName::SystemCalls)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn system_call_mut(&mut self) -> Option<&mut SystemCallPolicy> {
        if let Some(AppPolicyContainer::SystemCalls(policy)) =
            self.policies.get_mut(&PolicyName::SystemCalls)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn extension_point(&self) -> Option<&ExtensionPointPolicy> {
        if let Some(AppPolicyContainer::ExtensionPoints(policy)) =
            self.policies.get(&PolicyName::ExtensionPoints)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn extension_point_mut(&mut self) -> Option<&mut ExtensionPointPolicy> {
        if let Some(AppPolicyContainer::ExtensionPoints(policy)) =
            self.policies.get_mut(&PolicyName::ExtensionPoints)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn dynamic_code(&self) -> Option<&DynamicCodePolicy> {
        if let Some(AppPolicyContainer::DynamicCode(policy)) =
            self.policies.get(&PolicyName::DynamicCode)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn dynamic_code_mut(&mut self) -> Option<&mut DynamicCodePolicy> {
        if let Some(AppPolicyContainer::DynamicCode(policy)) =
            self.policies.get_mut(&PolicyName::DynamicCode)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn cfg(&self) -> Option<&CFGPolicy> {
        if let Some(AppPolicyContainer::ControlFlowGuard(policy)) =
            self.policies.get(&PolicyName::ControlFlowGuard)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn cfg_mut(&mut self) -> Option<&mut CFGPolicy> {
        if let Some(AppPolicyContainer::ControlFlowGuard(policy)) =
            self.policies.get_mut(&PolicyName::ControlFlowGuard)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn binary_signature(&self) -> Option<&BinarySignaturePolicy> {
        if let Some(AppPolicyContainer::SignedBinaries(policy)) =
            self.policies.get(&PolicyName::SignedBinaries)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn binary_signature_mut(&mut self) -> Option<&mut BinarySignaturePolicy> {
        if let Some(AppPolicyContainer::SignedBinaries(policy)) =
            self.policies.get_mut(&PolicyName::SignedBinaries)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn font_disable(&self) -> Option<&FontDisablePolicy> {
        if let Some(AppPolicyContainer::Fonts(policy)) = self.policies.get(&PolicyName::Fonts) {
            Some(policy)
        } else {
            None
        }
    }

    pub fn font_disable_mut(&mut self) -> Option<&mut FontDisablePolicy> {
        if let Some(AppPolicyContainer::Fonts(policy)) = self.policies.get_mut(&PolicyName::Fonts) {
            Some(policy)
        } else {
            None
        }
    }

    pub fn image_load(&self) -> Option<&ImageLoadPolicy> {
        if let Some(AppPolicyContainer::ImageLoad(policy)) =
            self.policies.get(&PolicyName::ImageLoad)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn image_load_mut(&mut self) -> Option<&mut ImageLoadPolicy> {
        if let Some(AppPolicyContainer::ImageLoad(policy)) =
            self.policies.get_mut(&PolicyName::ImageLoad)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn payload(&self) -> Option<&PayloadPolicy> {
        if let Some(AppPolicyContainer::Payload(policy)) = self.policies.get(&PolicyName::Payload) {
            Some(policy)
        } else {
            None
        }
    }

    pub fn payload_mut(&mut self) -> Option<&mut PayloadPolicy> {
        if let Some(AppPolicyContainer::Payload(policy)) =
            self.policies.get_mut(&PolicyName::Payload)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn child_process(&self) -> Option<&ChildProcessPolicy> {
        if let Some(AppPolicyContainer::ChildProcess(policy)) =
            self.policies.get(&PolicyName::ChildProcess)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn child_process_mut(&mut self) -> Option<&mut ChildProcessPolicy> {
        if let Some(AppPolicyContainer::ChildProcess(policy)) =
            self.policies.get_mut(&PolicyName::ChildProcess)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn user_shadow_stack(&self) -> Option<&UserShadowStackPolicy> {
        if let Some(AppPolicyContainer::UserShadowStack(policy)) =
            self.policies.get(&PolicyName::UserShadowStack)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn user_shadow_stack_mut(&mut self) -> Option<&mut UserShadowStackPolicy> {
        if let Some(AppPolicyContainer::UserShadowStack(policy)) =
            self.policies.get_mut(&PolicyName::UserShadowStack)
        {
            Some(policy)
        } else {
            None
        }
    }

    pub fn sehop(&self) -> Option<&SEHOPPolicy> {
        if let Some(AppPolicyContainer::SEHOP(policy)) = self.policies.get(&PolicyName::SEHOP) {
            Some(policy)
        } else {
            None
        }
    }

    pub fn sehop_mut(&mut self) -> Option<&mut SEHOPPolicy> {
        if let Some(AppPolicyContainer::SEHOP(policy)) = self.policies.get_mut(&PolicyName::SEHOP) {
            Some(policy)
        } else {
            None
        }
    }

    pub fn heap(&self) -> Option<&HeapPolicy> {
        if let Some(AppPolicyContainer::Heap(policy)) = self.policies.get(&PolicyName::Heap) {
            Some(policy)
        } else {
            None
        }
    }

    pub fn heap_mut(&mut self) -> Option<&mut HeapPolicy> {
        if let Some(AppPolicyContainer::Heap(policy)) = self.policies.get_mut(&PolicyName::Heap) {
            Some(policy)
        } else {
            None
        }
    }
}

impl fmt::Display for AppMitigations {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        writeln!(f, "Process:\t{}", self.process_name)?;
        writeln!(f, "Source: \t{}", self.source)?;
        let _is_registry = self.source != "Registry";
        for (policy_name, policy) in &self.policies {
            writeln!(f, "{:?}: {:?}", policy_name, policy)?;
        }
        Ok(())
    }
}

pub struct PolicyPairList;

#[derive(Debug, Clone)]
pub struct PolicyNamePair {
    pub parameter_name: MitigationOptions,
    pub policy_name: PolicyName,
    pub policy_option_name: PolicyOptionName,
    pub force_name: ForceName,
}

impl PolicyNamePair {
    pub fn new(
        parameter_name: MitigationOptions,
        policy_name: PolicyName,
        policy_option_name: PolicyOptionName,
        force_name: ForceName,
    ) -> Self {
        Self {
            parameter_name,
            policy_name,
            policy_option_name,
            force_name,
        }
    }
}

#[allow(dead_code)]
impl PolicyPairList {
    pub fn get_policy_pairs() -> Vec<PolicyNamePair> {
        vec![
            PolicyNamePair::new(
                MitigationOptions::DEP,
                PolicyName::DEP,
                PolicyOptionName::Enable,
                ForceName::DEP,
            ),
            PolicyNamePair::new(
                MitigationOptions::EmulateAtlThunks,
                PolicyName::DEP,
                PolicyOptionName::EmulateAtlThunks,
                ForceName::DEP,
            ),
            PolicyNamePair::new(
                MitigationOptions::ForceRelocateImages,
                PolicyName::ASLR,
                PolicyOptionName::ForceRelocateImages,
                ForceName::ForceRelocateImages,
            ),
            PolicyNamePair::new(
                MitigationOptions::RequireInfo,
                PolicyName::ASLR,
                PolicyOptionName::RequireInfo,
                ForceName::ForceRelocateImages,
            ),
            PolicyNamePair::new(
                MitigationOptions::BottomUp,
                PolicyName::ASLR,
                PolicyOptionName::BottomUp,
                ForceName::BottomUp,
            ),
            PolicyNamePair::new(
                MitigationOptions::HighEntropy,
                PolicyName::ASLR,
                PolicyOptionName::HighEntropy,
                ForceName::HighEntropy,
            ),
            PolicyNamePair::new(
                MitigationOptions::StrictHandle,
                PolicyName::StrictHandle,
                PolicyOptionName::Enable,
                ForceName::StrictHandle,
            ),
            PolicyNamePair::new(
                MitigationOptions::DisableWin32kSystemCalls,
                PolicyName::SystemCalls,
                PolicyOptionName::DisableWin32kSystemCalls,
                ForceName::SystemCall,
            ),
            PolicyNamePair::new(
                MitigationOptions::AuditSystemCall,
                PolicyName::SystemCalls,
                PolicyOptionName::Audit,
                ForceName::SystemCall,
            ),
            PolicyNamePair::new(
                MitigationOptions::DisableFsctlSystemCalls,
                PolicyName::SystemCalls,
                PolicyOptionName::DisableFsctlSystemCalls,
                ForceName::DisableFsctlSystem,
            ),
            PolicyNamePair::new(
                MitigationOptions::AuditFsctlSystemCall,
                PolicyName::SystemCalls,
                PolicyOptionName::AuditFsctlSystemCalls,
                ForceName::DisableFsctlSystem,
            ),
            PolicyNamePair::new(
                MitigationOptions::DisableExtensionPoints,
                PolicyName::ExtensionPoints,
                PolicyOptionName::DisableExtensionPoints,
                ForceName::ExtensionPoint,
            ),
            PolicyNamePair::new(
                MitigationOptions::BlockDynamicCode,
                PolicyName::DynamicCode,
                PolicyOptionName::BlockDynamicCode,
                ForceName::DynamicCode,
            ),
            PolicyNamePair::new(
                MitigationOptions::AllowThreadsToOptOut,
                PolicyName::DynamicCode,
                PolicyOptionName::AllowThreadsToOptOut,
                ForceName::DynamicCode,
            ),
            PolicyNamePair::new(
                MitigationOptions::AuditDynamicCode,
                PolicyName::DynamicCode,
                PolicyOptionName::Audit,
                ForceName::DynamicCode,
            ),
            PolicyNamePair::new(
                MitigationOptions::CFG,
                PolicyName::ControlFlowGuard,
                PolicyOptionName::Enable,
                ForceName::CFG,
            ),
            PolicyNamePair::new(
                MitigationOptions::SuppressExports,
                PolicyName::ControlFlowGuard,
                PolicyOptionName::SuppressExports,
                ForceName::CFG,
            ),
            PolicyNamePair::new(
                MitigationOptions::StrictCFG,
                PolicyName::ControlFlowGuard,
                PolicyOptionName::StrictControlFlowGuard,
                ForceName::StrictCFG,
            ),
            PolicyNamePair::new(
                MitigationOptions::MicrosoftSignedOnly,
                PolicyName::SignedBinaries,
                PolicyOptionName::MicrosoftSignedOnly,
                ForceName::MicrosoftSignedOnly,
            ),
            PolicyNamePair::new(
                MitigationOptions::AllowStoreSignedBinaries,
                PolicyName::SignedBinaries,
                PolicyOptionName::AllowStoreSignedBinaries,
                ForceName::MicrosoftSignedOnly,
            ),
            PolicyNamePair::new(
                MitigationOptions::EnforceModuleDependencySigning,
                PolicyName::SignedBinaries,
                PolicyOptionName::EnforceModuleDependencySigning,
                ForceName::EnforceModuleDependencySigning,
            ),
            PolicyNamePair::new(
                MitigationOptions::AuditMicrosoftSigned,
                PolicyName::SignedBinaries,
                PolicyOptionName::Audit,
                ForceName::MicrosoftSignedOnly,
            ),
            PolicyNamePair::new(
                MitigationOptions::AuditStoreSigned,
                PolicyName::SignedBinaries,
                PolicyOptionName::AuditStoreSigned,
                ForceName::MicrosoftSignedOnly,
            ),
            PolicyNamePair::new(
                MitigationOptions::DisableNonSystemFonts,
                PolicyName::Fonts,
                PolicyOptionName::DisableNonSystemFonts,
                ForceName::FontDisable,
            ),
            PolicyNamePair::new(
                MitigationOptions::AuditFont,
                PolicyName::Fonts,
                PolicyOptionName::Audit,
                ForceName::FontDisable,
            ),
            PolicyNamePair::new(
                MitigationOptions::BlockRemoteImageLoads,
                PolicyName::ImageLoad,
                PolicyOptionName::BlockRemoteImageLoads,
                ForceName::BlockRemoteImageLoads,
            ),
            PolicyNamePair::new(
                MitigationOptions::BlockLowLabelImageLoads,
                PolicyName::ImageLoad,
                PolicyOptionName::BlockLowLabelImageLoads,
                ForceName::BlockLowLabel,
            ),
            PolicyNamePair::new(
                MitigationOptions::PreferSystem32,
                PolicyName::ImageLoad,
                PolicyOptionName::PreferSystem32,
                ForceName::PreferSystem32,
            ),
            PolicyNamePair::new(
                MitigationOptions::AuditRemoteImageLoads,
                PolicyName::ImageLoad,
                PolicyOptionName::AuditRemoteImageLoads,
                ForceName::BlockRemoteImageLoads,
            ),
            PolicyNamePair::new(
                MitigationOptions::AuditLowLabelImageLoads,
                PolicyName::ImageLoad,
                PolicyOptionName::AuditLowLabelImageLoads,
                ForceName::BlockLowLabel,
            ),
            PolicyNamePair::new(
                MitigationOptions::AuditPreferSystem32,
                PolicyName::ImageLoad,
                PolicyOptionName::AuditPreferSystem32,
                ForceName::PreferSystem32,
            ),
            PolicyNamePair::new(
                MitigationOptions::EnableExportAddressFilter,
                PolicyName::Payload,
                PolicyOptionName::EnableExportAddressFilter,
                ForceName::EnableExportAddressFilter,
            ),
            PolicyNamePair::new(
                MitigationOptions::AuditEnableExportAddressFilter,
                PolicyName::Payload,
                PolicyOptionName::AuditEnableExportAddressFilter,
                ForceName::EnableExportAddressFilter,
            ),
            PolicyNamePair::new(
                MitigationOptions::EnableExportAddressFilterPlus,
                PolicyName::Payload,
                PolicyOptionName::EnableExportAddressFilterPlus,
                ForceName::EnableExportAddressFilterPlus,
            ),
            PolicyNamePair::new(
                MitigationOptions::AuditEnableExportAddressFilterPlus,
                PolicyName::Payload,
                PolicyOptionName::AuditEnableExportAddressFilterPlus,
                ForceName::EnableExportAddressFilterPlus,
            ),
            PolicyNamePair::new(
                MitigationOptions::EnableImportAddressFilter,
                PolicyName::Payload,
                PolicyOptionName::EnableImportAddressFilter,
                ForceName::EnableImportAddressFilter,
            ),
            PolicyNamePair::new(
                MitigationOptions::AuditEnableImportAddressFilter,
                PolicyName::Payload,
                PolicyOptionName::AuditEnableImportAddressFilter,
                ForceName::EnableImportAddressFilter,
            ),
            PolicyNamePair::new(
                MitigationOptions::EnableRopStackPivot,
                PolicyName::Payload,
                PolicyOptionName::EnableRopStackPivot,
                ForceName::EnableRopStackPivot,
            ),
            PolicyNamePair::new(
                MitigationOptions::AuditEnableRopStackPivot,
                PolicyName::Payload,
                PolicyOptionName::AuditEnableRopStackPivot,
                ForceName::EnableRopStackPivot,
            ),
            PolicyNamePair::new(
                MitigationOptions::EnableRopCallerCheck,
                PolicyName::Payload,
                PolicyOptionName::EnableRopCallerCheck,
                ForceName::EnableRopCallerCheck,
            ),
            PolicyNamePair::new(
                MitigationOptions::AuditEnableRopCallerCheck,
                PolicyName::Payload,
                PolicyOptionName::AuditEnableRopCallerCheck,
                ForceName::EnableRopCallerCheck,
            ),
            PolicyNamePair::new(
                MitigationOptions::EnableRopSimExec,
                PolicyName::Payload,
                PolicyOptionName::EnableRopSimExec,
                ForceName::EnableRopSimExec,
            ),
            PolicyNamePair::new(
                MitigationOptions::AuditEnableRopSimExec,
                PolicyName::Payload,
                PolicyOptionName::AuditEnableRopSimExec,
                ForceName::EnableRopSimExec,
            ),
            PolicyNamePair::new(
                MitigationOptions::SEHOP,
                PolicyName::SEHOP,
                PolicyOptionName::Enable,
                ForceName::SEHOP,
            ),
            PolicyNamePair::new(
                MitigationOptions::AuditSEHOP,
                PolicyName::SEHOP,
                PolicyOptionName::Audit,
                ForceName::SEHOP,
            ),
            PolicyNamePair::new(
                MitigationOptions::SEHOPTelemetry,
                PolicyName::SEHOP,
                PolicyOptionName::TelemetryOnly,
                ForceName::SEHOP,
            ),
            PolicyNamePair::new(
                MitigationOptions::TerminateOnError,
                PolicyName::Heap,
                PolicyOptionName::TerminateOnError,
                ForceName::Heap,
            ),
            PolicyNamePair::new(
                MitigationOptions::DisallowChildProcessCreation,
                PolicyName::ChildProcess,
                PolicyOptionName::DisallowChildProcessCreation,
                ForceName::ChildProcess,
            ),
            PolicyNamePair::new(
                MitigationOptions::AuditChildProcess,
                PolicyName::ChildProcess,
                PolicyOptionName::Audit,
                ForceName::ChildProcess,
            ),
            PolicyNamePair::new(
                MitigationOptions::UserShadowStack,
                PolicyName::UserShadowStack,
                PolicyOptionName::UserShadowStack,
                ForceName::UserShadowStack,
            ),
            PolicyNamePair::new(
                MitigationOptions::UserShadowStackStrictMode,
                PolicyName::UserShadowStack,
                PolicyOptionName::UserShadowStackStrictMode,
                ForceName::UserShadowStack,
            ),
            PolicyNamePair::new(
                MitigationOptions::AuditUserShadowStack,
                PolicyName::UserShadowStack,
                PolicyOptionName::AuditUserShadowStack,
                ForceName::UserShadowStack,
            ),
        ]
    }

    pub fn get_parameter_list() -> Vec<MitigationOptions> {
        Self::get_policy_pairs()
            .iter()
            .map(|pair| pair.parameter_name)
            .collect()
    }

    pub fn get_count() -> usize {
        Self::get_policy_pairs().len()
    }

    pub fn get_pair_by_id(id: usize) -> Option<PolicyNamePair> {
        let pairs = Self::get_policy_pairs();
        pairs.get(id).cloned()
    }
}

use serde::{Deserialize, Serialize};

// Adding Serialize and Deserialize to all structs that need JSON serialization
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProcessMitigationsJson {
    pub process_name: String,
    pub source: String,
    pub id: u32,
    pub policies: std::collections::HashMap<String, PolicyContainerJson>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AppMitigationsJson {
    pub process_name: String,
    pub source: String,
    pub policies: std::collections::HashMap<String, AppPolicyContainerJson>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum PolicyContainerJson {
    Dep {
        enable: String,
        emulate_atl_thunks: String,
        flags: u32,
    },
    Aslr {
        force_relocate_images: String,
        require_info: String,
        bottom_up: String,
        high_entropy: String,
        flags: u32,
    },
    StrictHandle {
        enable: String,
        flags: u32,
    },
    SystemCalls {
        disable_win32k_system_calls: String,
        audit: String,
        disable_fsctl_system_calls: String,
        audit_fsctl_system_calls: String,
        flags: u32,
    },
    ExtensionPoints {
        disable_extension_points: String,
        flags: u32,
    },
    DynamicCode {
        block_dynamic_code: String,
        allow_threads_to_opt_out: String,
        audit: String,
        flags: u32,
    },
    ControlFlowGuard {
        enable: String,
        suppress_exports: String,
        strict_control_flow_guard: String,
        flags: u32,
    },
    SignedBinaries {
        microsoft_signed_only: String,
        allow_store_signed_binaries: String,
        audit: String,
        audit_store_signed: String,
        flags: u32,
    },
    Fonts {
        disable_non_system_fonts: String,
        audit: String,
        flags: u32,
    },
    ImageLoad {
        block_remote_image_loads: String,
        block_low_label_image_loads: String,
        prefer_system32: String,
        audit_remote_image_loads: String,
        audit_low_label_image_loads: String,
        audit_prefer_system32: String,
        flags: u32,
    },
    Payload {
        enable_export_address_filter: String,
        audit_enable_export_address_filter: String,
        enable_export_address_filter_plus: String,
        audit_enable_export_address_filter_plus: String,
        enable_import_address_filter: String,
        audit_enable_import_address_filter: String,
        enable_rop_stack_pivot: String,
        audit_enable_rop_stack_pivot: String,
        enable_rop_caller_check: String,
        audit_enable_rop_caller_check: String,
        enable_rop_sim_exec: String,
        audit_enable_rop_sim_exec: String,
        flags: u32,
    },
    ChildProcess {
        disallow_child_process_creation: String,
        audit: String,
        flags: u32,
    },
    UserShadowStack {
        user_shadow_stack: String,
        user_shadow_stack_strict_mode: String,
        audit_user_shadow_stack: String,
        set_context_ip_validation: String,
        audit_set_context_ip_validation: String,
        block_non_cet_binaries: String,
        block_non_cet_binaries_non_ehcont: String,
        audit_block_non_cet_binaries: String,
        flags: u32,
    },
    SEHOP {
        enable: String,
        telemetry_only: String,
        audit: String,
        flags: u32,
    },
}

// FOR JSON
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum AppPolicyContainerJson {
    Dep {
        enable: String,
        emulate_atl_thunks: String,
        override_dep: bool,
        flags: u32,
    },
    Aslr {
        force_relocate_images: String,
        require_info: String,
        bottom_up: String,
        high_entropy: String,
        override_force_relocate_images: bool,
        override_bottom_up: bool,
        override_high_entropy: bool,
        flags: u32,
    },
    StrictHandle {
        enable: String,
        override_strict_handle: bool,
        flags: u32,
    },
    SystemCalls {
        disable_win32k_system_calls: String,
        audit: String,
        disable_fsctl_system_calls: String,
        audit_fsctl_system_calls: String,
        override_system_call: bool,
        override_fsctl_system_call: bool,
        flags: u32,
    },
    ExtensionPoints {
        disable_extension_points: String,
        override_extension_point: bool,
        flags: u32,
    },
    DynamicCode {
        block_dynamic_code: String,
        allow_threads_to_opt_out: String,
        audit: String,
        override_dynamic_code: bool,
        flags: u32,
    },
    ControlFlowGuard {
        enable: String,
        suppress_exports: String,
        strict_control_flow_guard: String,
        override_cfg: bool,
        override_strict_cfg: bool,
        flags: u32,
    },
    SignedBinaries {
        microsoft_signed_only: String,
        allow_store_signed_binaries: String,
        enforce_module_dependency_signing: String,
        audit: String,
        audit_store_signed: String,
        audit_enforce_module_dependency_signing: String,
        override_microsoft_signed_only: bool,
        override_enforce_module_dependency_signing: bool,
        flags: u32,
    },
    Fonts {
        disable_non_system_fonts: String,
        audit: String,
        override_font_disable: bool,
        flags: u32,
    },
    ImageLoad {
        block_remote_image_loads: String,
        block_low_label_image_loads: String,
        prefer_system32: String,
        audit_remote_image_loads: String,
        audit_low_label_image_loads: String,
        audit_prefer_system32: String,
        override_block_remote_image_loads: bool,
        override_block_low_label: bool,
        override_prefer_system32: bool,
        flags: u32,
    },
    Payload {
        enable_export_address_filter: String,
        audit_enable_export_address_filter: String,
        enable_export_address_filter_plus: String,
        audit_enable_export_address_filter_plus: String,
        enable_import_address_filter: String,
        audit_enable_import_address_filter: String,
        enable_rop_stack_pivot: String,
        audit_enable_rop_stack_pivot: String,
        enable_rop_caller_check: String,
        audit_enable_rop_caller_check: String,
        enable_rop_sim_exec: String,
        audit_enable_rop_sim_exec: String,
        override_enable_export_address_filter: bool,
        override_enable_export_address_filter_plus: bool,
        override_enable_import_address_filter: bool,
        override_enable_rop_stack_pivot: bool,
        override_enable_rop_caller_check: bool,
        override_enable_rop_sim_exec: bool,
        eaf_modules: Vec<String>,
        flags: u32,
    },
    ChildProcess {
        disallow_child_process_creation: String,
        audit: String,
        override_child_process: bool,
        flags: u32,
    },
    UserShadowStack {
        user_shadow_stack: String,
        user_shadow_stack_strict_mode: String,
        audit_user_shadow_stack: String,
        set_context_ip_validation: String,
        audit_set_context_ip_validation: String,
        block_non_cet_binaries: String,
        block_non_cet_binaries_non_ehcont: String,
        audit_block_non_cet_binaries: String,
        override_user_shadow_stack: bool,
        flags: u32,
    },
    SEHOP {
        enable: String,
        telemetry_only: String,
        audit: String,
        override_sehop: bool,
        flags: u32,
    },
    Heap {
        terminate_on_error: String,
        override_heap: bool,
        flags: u32,
    },
}

impl ProcessMitigations {
    pub fn to_json(&self) -> ProcessMitigationsJson {
        fn option_value_to_string(value: OptionValue) -> String {
            match value {
                OptionValue::NotSet => "NotSet".to_string(),
                OptionValue::On => "On".to_string(),
                OptionValue::Off => "Off".to_string(),
                OptionValue::Error => "Error".to_string(),
            }
        }

        let mut policies_json = std::collections::HashMap::new();

        for (policy_name, policy) in &self.policies {
            let policy_json = match policy {
                PolicyContainer::Dep(p) => PolicyContainerJson::Dep {
                    enable: option_value_to_string(p.enable()),
                    emulate_atl_thunks: option_value_to_string(p.emulate_atl_thunks()),
                    flags: p.flags(),
                },
                PolicyContainer::Aslr(p) => PolicyContainerJson::Aslr {
                    force_relocate_images: option_value_to_string(p.force_relocate_images()),
                    require_info: option_value_to_string(p.require_info()),
                    bottom_up: option_value_to_string(p.bottom_up()),
                    high_entropy: option_value_to_string(p.high_entropy()),
                    flags: p.flags(),
                },
                PolicyContainer::StrictHandle(p) => PolicyContainerJson::StrictHandle {
                    enable: option_value_to_string(p.enable()),
                    flags: p.flags(),
                },
                PolicyContainer::SystemCalls(p) => PolicyContainerJson::SystemCalls {
                    disable_win32k_system_calls: option_value_to_string(
                        p.disable_win32k_system_calls(),
                    ),
                    audit: option_value_to_string(p.audit()),
                    disable_fsctl_system_calls: option_value_to_string(
                        p.disable_fsctl_system_calls(),
                    ),
                    audit_fsctl_system_calls: option_value_to_string(p.audit_fsctl_system_calls()),
                    flags: p.flags(),
                },
                PolicyContainer::ExtensionPoints(p) => PolicyContainerJson::ExtensionPoints {
                    disable_extension_points: option_value_to_string(p.disable_extension_points()),
                    flags: p.flags(),
                },
                PolicyContainer::DynamicCode(p) => PolicyContainerJson::DynamicCode {
                    block_dynamic_code: option_value_to_string(p.block_dynamic_code()),
                    allow_threads_to_opt_out: option_value_to_string(p.allow_threads_to_opt_out()),
                    audit: option_value_to_string(p.audit()),
                    flags: p.flags(),
                },
                PolicyContainer::ControlFlowGuard(p) => PolicyContainerJson::ControlFlowGuard {
                    enable: option_value_to_string(p.enable()),
                    suppress_exports: option_value_to_string(p.suppress_exports()),
                    strict_control_flow_guard: option_value_to_string(
                        p.strict_control_flow_guard(),
                    ),
                    flags: p.flags(),
                },
                PolicyContainer::SignedBinaries(p) => PolicyContainerJson::SignedBinaries {
                    microsoft_signed_only: option_value_to_string(p.microsoft_signed_only()),
                    allow_store_signed_binaries: option_value_to_string(
                        p.allow_store_signed_binaries(),
                    ),
                    audit: option_value_to_string(p.audit()),
                    audit_store_signed: option_value_to_string(p.audit_store_signed()),
                    flags: p.flags(),
                },
                PolicyContainer::Fonts(p) => PolicyContainerJson::Fonts {
                    disable_non_system_fonts: option_value_to_string(p.disable_non_system_fonts()),
                    audit: option_value_to_string(p.audit()),
                    flags: p.flags(),
                },
                PolicyContainer::ImageLoad(p) => PolicyContainerJson::ImageLoad {
                    block_remote_image_loads: option_value_to_string(p.block_remote_image_loads()),
                    block_low_label_image_loads: option_value_to_string(
                        p.block_low_label_image_loads(),
                    ),
                    prefer_system32: option_value_to_string(p.prefer_system32()),
                    audit_remote_image_loads: option_value_to_string(p.audit_remote_image_loads()),
                    audit_low_label_image_loads: option_value_to_string(
                        p.audit_low_label_image_loads(),
                    ),
                    audit_prefer_system32: option_value_to_string(p.audit_prefer_system32()),
                    flags: p.flags(),
                },
                PolicyContainer::Payload(p) => PolicyContainerJson::Payload {
                    enable_export_address_filter: option_value_to_string(
                        p.enable_export_address_filter(),
                    ),
                    audit_enable_export_address_filter: option_value_to_string(
                        p.audit_enable_export_address_filter(),
                    ),
                    enable_export_address_filter_plus: option_value_to_string(
                        p.enable_export_address_filter_plus(),
                    ),
                    audit_enable_export_address_filter_plus: option_value_to_string(
                        p.audit_enable_export_address_filter_plus(),
                    ),
                    enable_import_address_filter: option_value_to_string(
                        p.enable_import_address_filter(),
                    ),
                    audit_enable_import_address_filter: option_value_to_string(
                        p.audit_enable_import_address_filter(),
                    ),
                    enable_rop_stack_pivot: option_value_to_string(p.enable_rop_stack_pivot()),
                    audit_enable_rop_stack_pivot: option_value_to_string(
                        p.audit_enable_rop_stack_pivot(),
                    ),
                    enable_rop_caller_check: option_value_to_string(p.enable_rop_caller_check()),
                    audit_enable_rop_caller_check: option_value_to_string(
                        p.audit_enable_rop_caller_check(),
                    ),
                    enable_rop_sim_exec: option_value_to_string(p.enable_rop_sim_exec()),
                    audit_enable_rop_sim_exec: option_value_to_string(
                        p.audit_enable_rop_sim_exec(),
                    ),
                    flags: p.flags(),
                },
                PolicyContainer::ChildProcess(p) => PolicyContainerJson::ChildProcess {
                    disallow_child_process_creation: option_value_to_string(
                        p.disallow_child_process_creation(),
                    ),
                    audit: option_value_to_string(p.audit()),
                    flags: p.flags(),
                },
                PolicyContainer::UserShadowStack(p) => PolicyContainerJson::UserShadowStack {
                    user_shadow_stack: option_value_to_string(p.user_shadow_stack()),
                    user_shadow_stack_strict_mode: option_value_to_string(
                        p.user_shadow_stack_strict_mode(),
                    ),
                    audit_user_shadow_stack: option_value_to_string(p.audit_user_shadow_stack()),
                    set_context_ip_validation: option_value_to_string(
                        p.set_context_ip_validation(),
                    ),
                    audit_set_context_ip_validation: option_value_to_string(
                        p.audit_set_context_ip_validation(),
                    ),
                    block_non_cet_binaries: option_value_to_string(p.block_non_cet_binaries()),
                    block_non_cet_binaries_non_ehcont: option_value_to_string(
                        p.block_non_cet_binaries_non_ehcont(),
                    ),
                    audit_block_non_cet_binaries: option_value_to_string(
                        p.audit_block_non_cet_binaries(),
                    ),
                    flags: p.flags(),
                },
                PolicyContainer::SEHOP(p) => PolicyContainerJson::SEHOP {
                    enable: option_value_to_string(p.enable()),
                    telemetry_only: option_value_to_string(p.telemetry_only()),
                    audit: option_value_to_string(p.audit()),
                    flags: p.flags(),
                },
            };

            policies_json.insert(policy_name.to_string_value().to_string(), policy_json);
        }

        ProcessMitigationsJson {
            process_name: self.process_name.clone(),
            source: self.source.clone(),
            id: self.id,
            policies: policies_json,
        }
    }
}
// FOR JSON
impl AppMitigations {
    pub fn to_json(&self) -> AppMitigationsJson {
        fn option_value_to_string(value: OptionValue) -> String {
            match value {
                OptionValue::NotSet => "NotSet".to_string(),
                OptionValue::On => "On".to_string(),
                OptionValue::Off => "Off".to_string(),
                OptionValue::Error => "Error".to_string(),
            }
        }

        let mut policies_json = std::collections::HashMap::new();

        for (policy_name, policy) in &self.policies {
            let policy_json = match policy {
                AppPolicyContainer::Dep(p) => AppPolicyContainerJson::Dep {
                    enable: option_value_to_string(p.enable()),
                    emulate_atl_thunks: option_value_to_string(p.emulate_atl_thunks()),
                    override_dep: p.override_dep(),
                    flags: p.flags(),
                },
                AppPolicyContainer::Aslr(p) => AppPolicyContainerJson::Aslr {
                    force_relocate_images: option_value_to_string(p.force_relocate_images()),
                    require_info: option_value_to_string(p.require_info()),
                    bottom_up: option_value_to_string(p.bottom_up()),
                    high_entropy: option_value_to_string(p.high_entropy()),
                    override_force_relocate_images: p.override_force_relocate_images(),
                    override_bottom_up: p.override_bottom_up(),
                    override_high_entropy: p.override_high_entropy(),
                    flags: p.flags(),
                },
                AppPolicyContainer::StrictHandle(p) => AppPolicyContainerJson::StrictHandle {
                    enable: option_value_to_string(p.enable()),
                    override_strict_handle: p.override_strict_handle(),
                    flags: p.flags(),
                },
                AppPolicyContainer::SystemCalls(p) => AppPolicyContainerJson::SystemCalls {
                    disable_win32k_system_calls: option_value_to_string(
                        p.disable_win32k_system_calls(),
                    ),
                    audit: option_value_to_string(p.audit()),
                    disable_fsctl_system_calls: option_value_to_string(
                        p.disable_fsctl_system_calls(),
                    ),
                    audit_fsctl_system_calls: option_value_to_string(p.audit_fsctl_system_calls()),
                    override_system_call: p.override_system_call(),
                    override_fsctl_system_call: p.override_fsctl_system_call(),
                    flags: p.flags(),
                },
                AppPolicyContainer::ExtensionPoints(p) => AppPolicyContainerJson::ExtensionPoints {
                    disable_extension_points: option_value_to_string(p.disable_extension_points()),
                    override_extension_point: p.override_extension_point(),
                    flags: p.flags(),
                },
                AppPolicyContainer::DynamicCode(p) => AppPolicyContainerJson::DynamicCode {
                    block_dynamic_code: option_value_to_string(p.block_dynamic_code()),
                    allow_threads_to_opt_out: option_value_to_string(p.allow_threads_to_opt_out()),
                    audit: option_value_to_string(p.audit()),
                    override_dynamic_code: p.override_dynamic_code(),
                    flags: p.flags(),
                },
                AppPolicyContainer::ControlFlowGuard(p) => {
                    AppPolicyContainerJson::ControlFlowGuard {
                        enable: option_value_to_string(p.enable()),
                        suppress_exports: option_value_to_string(p.suppress_exports()),
                        strict_control_flow_guard: option_value_to_string(
                            p.strict_control_flow_guard(),
                        ),
                        override_cfg: p.override_cfg(),
                        override_strict_cfg: p.override_strict_cfg(),
                        flags: p.flags(),
                    }
                }
                AppPolicyContainer::SignedBinaries(p) => AppPolicyContainerJson::SignedBinaries {
                    microsoft_signed_only: option_value_to_string(p.microsoft_signed_only()),
                    allow_store_signed_binaries: option_value_to_string(
                        p.allow_store_signed_binaries(),
                    ),
                    enforce_module_dependency_signing: option_value_to_string(
                        p.enforce_module_dependency_signing(),
                    ),
                    audit: option_value_to_string(p.audit()),
                    audit_store_signed: option_value_to_string(p.audit_store_signed()),
                    audit_enforce_module_dependency_signing: option_value_to_string(
                        p.audit_enforce_module_dependency_signing(),
                    ),
                    override_microsoft_signed_only: p.override_microsoft_signed_only(),
                    override_enforce_module_dependency_signing: p
                        .override_enforce_module_dependency_signing(),
                    flags: p.flags(),
                },
                AppPolicyContainer::Fonts(p) => AppPolicyContainerJson::Fonts {
                    disable_non_system_fonts: option_value_to_string(p.disable_non_system_fonts()),
                    audit: option_value_to_string(p.audit()),
                    override_font_disable: p.override_font_disable(),
                    flags: p.flags(),
                },
                AppPolicyContainer::ImageLoad(p) => AppPolicyContainerJson::ImageLoad {
                    block_remote_image_loads: option_value_to_string(p.block_remote_image_loads()),
                    block_low_label_image_loads: option_value_to_string(
                        p.block_low_label_image_loads(),
                    ),
                    prefer_system32: option_value_to_string(p.prefer_system32()),
                    audit_remote_image_loads: option_value_to_string(p.audit_remote_image_loads()),
                    audit_low_label_image_loads: option_value_to_string(
                        p.audit_low_label_image_loads(),
                    ),
                    audit_prefer_system32: option_value_to_string(p.audit_prefer_system32()),
                    override_block_remote_image_loads: p.override_block_remote_image_loads(),
                    override_block_low_label: p.override_block_low_label(),
                    override_prefer_system32: p.override_prefer_system32(),
                    flags: p.flags(),
                },
                AppPolicyContainer::Payload(p) => AppPolicyContainerJson::Payload {
                    enable_export_address_filter: option_value_to_string(
                        p.enable_export_address_filter(),
                    ),
                    audit_enable_export_address_filter: option_value_to_string(
                        p.audit_enable_export_address_filter(),
                    ),
                    enable_export_address_filter_plus: option_value_to_string(
                        p.enable_export_address_filter_plus(),
                    ),
                    audit_enable_export_address_filter_plus: option_value_to_string(
                        p.audit_enable_export_address_filter_plus(),
                    ),
                    enable_import_address_filter: option_value_to_string(
                        p.enable_import_address_filter(),
                    ),
                    audit_enable_import_address_filter: option_value_to_string(
                        p.audit_enable_import_address_filter(),
                    ),
                    enable_rop_stack_pivot: option_value_to_string(p.enable_rop_stack_pivot()),
                    audit_enable_rop_stack_pivot: option_value_to_string(
                        p.audit_enable_rop_stack_pivot(),
                    ),
                    enable_rop_caller_check: option_value_to_string(p.enable_rop_caller_check()),
                    audit_enable_rop_caller_check: option_value_to_string(
                        p.audit_enable_rop_caller_check(),
                    ),
                    enable_rop_sim_exec: option_value_to_string(p.enable_rop_sim_exec()),
                    audit_enable_rop_sim_exec: option_value_to_string(
                        p.audit_enable_rop_sim_exec(),
                    ),
                    override_enable_export_address_filter: p
                        .override_enable_export_address_filter(),
                    override_enable_export_address_filter_plus: p
                        .override_enable_export_address_filter_plus(),
                    override_enable_import_address_filter: p
                        .override_enable_import_address_filter(),
                    override_enable_rop_stack_pivot: p.override_enable_rop_stack_pivot(),
                    override_enable_rop_caller_check: p.override_enable_rop_caller_check(),
                    override_enable_rop_sim_exec: p.override_enable_rop_sim_exec(),
                    eaf_modules: p.eaf_modules.clone(),
                    flags: p.flags(),
                },
                AppPolicyContainer::ChildProcess(p) => AppPolicyContainerJson::ChildProcess {
                    disallow_child_process_creation: option_value_to_string(
                        p.disallow_child_process_creation(),
                    ),
                    audit: option_value_to_string(p.audit()),
                    override_child_process: p.override_child_process(),
                    flags: p.flags(),
                },
                AppPolicyContainer::UserShadowStack(p) => AppPolicyContainerJson::UserShadowStack {
                    user_shadow_stack: option_value_to_string(p.user_shadow_stack()),
                    user_shadow_stack_strict_mode: option_value_to_string(
                        p.user_shadow_stack_strict_mode(),
                    ),
                    audit_user_shadow_stack: option_value_to_string(p.audit_user_shadow_stack()),
                    set_context_ip_validation: option_value_to_string(
                        p.set_context_ip_validation(),
                    ),
                    audit_set_context_ip_validation: option_value_to_string(
                        p.audit_set_context_ip_validation(),
                    ),
                    block_non_cet_binaries: option_value_to_string(p.block_non_cet_binaries()),
                    block_non_cet_binaries_non_ehcont: option_value_to_string(
                        p.block_non_cet_binaries_non_ehcont(),
                    ),
                    audit_block_non_cet_binaries: option_value_to_string(
                        p.audit_block_non_cet_binaries(),
                    ),
                    override_user_shadow_stack: p.override_user_shadow_stack(),
                    flags: p.flags(),
                },
                AppPolicyContainer::SEHOP(p) => AppPolicyContainerJson::SEHOP {
                    enable: option_value_to_string(p.enable()),
                    telemetry_only: option_value_to_string(p.telemetry_only()),
                    audit: option_value_to_string(p.audit()),
                    override_sehop: p.override_sehop(),
                    flags: p.flags(),
                },
                AppPolicyContainer::Heap(p) => AppPolicyContainerJson::Heap {
                    terminate_on_error: option_value_to_string(p.terminate_on_error()),
                    override_heap: p.override_heap(),
                    flags: p.flags(),
                },
            };

            policies_json.insert(policy_name.to_string_value().to_string(), policy_json);
        }

        AppMitigationsJson {
            process_name: self.process_name.clone(),
            source: self.source.clone(),
            policies: policies_json,
        }
    }
}
